tty_subr.c revision 1.30 1 /* $NetBSD: tty_subr.c,v 1.30 2007/11/07 15:56:22 ad Exp $ */
2
3 /*
4 * Copyright (c) 1993, 1994 Theo de Raadt
5 * All rights reserved.
6 *
7 * Per Lindqvist <pgd (at) 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.30 2007/11/07 15:56:22 ad 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 static 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(struct clist *clp, int size, int quot)
74 {
75
76 clp->c_cs = malloc(size, M_TTYS, M_WAITOK);
77 if (!clp->c_cs)
78 return (-1);
79 memset(clp->c_cs, 0, size);
80
81 if(quot) {
82 clp->c_cq = malloc(QMEM(size), M_TTYS, M_WAITOK);
83 if (!clp->c_cq) {
84 free(clp->c_cs, M_TTYS);
85 return (-1);
86 }
87 memset(clp->c_cq, 0, 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
96 cv_init(&clp->c_cv, "tty");
97 cv_init(&clp->c_cvf, "tty");
98 return (0);
99 }
100
101 void
102 clfree(struct clist *clp)
103 {
104 if(clp->c_cs)
105 free(clp->c_cs, M_TTYS);
106 if(clp->c_cq)
107 free(clp->c_cq, M_TTYS);
108 clp->c_cs = clp->c_cq = (u_char *)0;
109 cv_destroy(&clp->c_cv);
110 cv_destroy(&clp->c_cvf);
111 }
112
113
114 /*
115 * Get a character from a clist.
116 */
117 int
118 getc(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(struct clist *clp, u_char *cp, int count)
152 {
153 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 memcpy(p, clp->c_cf, 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 int
184 ndqb(struct clist *clp, int flag)
185 {
186 int count = 0;
187 int i;
188 int cc;
189 int s;
190
191 s = spltty();
192 if ((cc = clp->c_cc) == 0)
193 goto out;
194
195 if (flag == 0) {
196 count = clp->c_cl - clp->c_cf;
197 if (count <= 0)
198 count = clp->c_ce - clp->c_cf;
199 goto out;
200 }
201
202 i = clp->c_cf - clp->c_cs;
203 if (flag & TTY_QUOTE) {
204 while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) ||
205 isset(clp->c_cq, i))) {
206 count++;
207 if (i == clp->c_cn)
208 break;
209 }
210 } else {
211 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) {
212 count++;
213 if (i == clp->c_cn)
214 break;
215 }
216 }
217 out:
218 splx(s);
219 return count;
220 }
221
222 /*
223 * Flush count bytes from clist.
224 */
225 void
226 ndflush(struct clist *clp, int count)
227 {
228 int cc;
229 int s;
230
231 s = spltty();
232 if (count == clp->c_cc) {
233 clp->c_cc = 0;
234 clp->c_cf = clp->c_cl = (u_char *)0;
235 goto out;
236 }
237 /* optimize this while loop */
238 while (count > 0 && clp->c_cc > 0) {
239 cc = clp->c_cl - clp->c_cf;
240 if (clp->c_cf >= clp->c_cl)
241 cc = clp->c_ce - clp->c_cf;
242 if (cc > count)
243 cc = count;
244 count -= cc;
245 clp->c_cc -= cc;
246 clp->c_cf += cc;
247 if (clp->c_cf == clp->c_ce)
248 clp->c_cf = clp->c_cs;
249 }
250 if (clp->c_cc == 0)
251 clp->c_cf = clp->c_cl = (u_char *)0;
252 out:
253 splx(s);
254 }
255
256 /*
257 * Put a character into the output queue.
258 */
259 int
260 putc(int c, struct clist *clp)
261 {
262 int i;
263 int s;
264
265 s = spltty();
266 if (clp->c_cc == clp->c_cn)
267 goto out;
268
269 if (clp->c_cc == 0) {
270 if (!clp->c_cs) {
271 #if defined(DIAGNOSTIC) || 1
272 printf("putc: required clalloc\n");
273 #endif
274 if(clalloc(clp, 1024, 1)) {
275 out:
276 splx(s);
277 return -1;
278 }
279 }
280 clp->c_cf = clp->c_cl = clp->c_cs;
281 }
282
283 *clp->c_cl = c & 0xff;
284 i = clp->c_cl - clp->c_cs;
285 if (clp->c_cq) {
286 #ifdef QBITS
287 if (c & TTY_QUOTE)
288 setbit(clp->c_cq, i);
289 else
290 clrbit(clp->c_cq, i);
291 #else
292 q = clp->c_cq + i;
293 *q = (c & TTY_QUOTE) ? 1 : 0;
294 #endif
295 }
296 clp->c_cc++;
297 clp->c_cl++;
298 if (clp->c_cl == clp->c_ce)
299 clp->c_cl = clp->c_cs;
300 splx(s);
301 return 0;
302 }
303
304 #ifdef QBITS
305 /*
306 * optimized version of
307 *
308 * for (i = 0; i < len; i++)
309 * clrbit(cp, off + len);
310 */
311 static void
312 clrbits(u_char *cp, int off, int len)
313 {
314 int sby, sbi, eby, ebi;
315 int i;
316 u_char mask;
317
318 if(len==1) {
319 clrbit(cp, off);
320 return;
321 }
322
323 sby = off / NBBY;
324 sbi = off % NBBY;
325 eby = (off+len) / NBBY;
326 ebi = (off+len) % NBBY;
327 if (sby == eby) {
328 mask = ((1 << (ebi - sbi)) - 1) << sbi;
329 cp[sby] &= ~mask;
330 } else {
331 mask = (1<<sbi) - 1;
332 cp[sby++] &= mask;
333
334 mask = (1<<ebi) - 1;
335 cp[eby] &= ~mask;
336
337 for (i = sby; i < eby; i++)
338 cp[i] = 0x00;
339 }
340 }
341 #endif
342
343 /*
344 * Copy buffer to clist.
345 * Return number of bytes not transfered.
346 */
347 int
348 b_to_q(const u_char *cp, int count, struct clist *clp)
349 {
350 int cc;
351 const u_char *p = cp;
352 int s;
353
354 if (count <= 0)
355 return 0;
356
357 s = spltty();
358 if (clp->c_cc == clp->c_cn)
359 goto out;
360
361 if (clp->c_cc == 0) {
362 if (!clp->c_cs) {
363 #if defined(DIAGNOSTIC) || 1
364 printf("b_to_q: required clalloc\n");
365 #endif
366 if(clalloc(clp, 1024, 1))
367 goto out;
368 }
369 clp->c_cf = clp->c_cl = clp->c_cs;
370 }
371
372 /* optimize this while loop */
373 while (count > 0 && clp->c_cc < clp->c_cn) {
374 cc = clp->c_ce - clp->c_cl;
375 if (clp->c_cf > clp->c_cl)
376 cc = clp->c_cf - clp->c_cl;
377 if (cc > count)
378 cc = count;
379 memcpy(clp->c_cl, p, cc);
380 if (clp->c_cq) {
381 #ifdef QBITS
382 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc);
383 #else
384 memset(clp->c_cl - clp->c_cs + clp->c_cq, 0, cc);
385 #endif
386 }
387 p += cc;
388 count -= cc;
389 clp->c_cc += cc;
390 clp->c_cl += cc;
391 if (clp->c_cl == clp->c_ce)
392 clp->c_cl = clp->c_cs;
393 }
394 out:
395 splx(s);
396 return count;
397 }
398
399 static int cc;
400
401 /*
402 * Given a non-NULL pointer into the clist return the pointer
403 * to the next character in the list or return NULL if no more chars.
404 *
405 * Callers must not allow getc's to happen between firstc's and getc's
406 * so that the pointer becomes invalid. Note that interrupts are NOT
407 * masked.
408 */
409 u_char *
410 nextc(struct clist *clp, u_char *cp, 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(struct clist *clp, int *c)
450 {
451 u_char *cp;
452
453 cc = clp->c_cc;
454 if (cc == 0)
455 return NULL;
456 cp = clp->c_cf;
457 *c = *cp & 0xff;
458 if(clp->c_cq) {
459 #ifdef QBITS
460 if (isset(clp->c_cq, cp - clp->c_cs))
461 *c |= TTY_QUOTE;
462 #else
463 if (*(cp - clp->c_cs + clp->c_cq))
464 *c |= TTY_QUOTE;
465 #endif
466 }
467 return clp->c_cf;
468 }
469
470 /*
471 * Remove the last character in the clist and return it.
472 */
473 int
474 unputc(struct clist *clp)
475 {
476 unsigned int c = -1;
477 int s;
478
479 s = spltty();
480 if (clp->c_cc == 0)
481 goto out;
482
483 if (clp->c_cl == clp->c_cs)
484 clp->c_cl = clp->c_ce - 1;
485 else
486 --clp->c_cl;
487 clp->c_cc--;
488
489 c = *clp->c_cl & 0xff;
490 if (clp->c_cq) {
491 #ifdef QBITS
492 if (isset(clp->c_cq, clp->c_cl - clp->c_cs))
493 c |= TTY_QUOTE;
494 #else
495 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
496 c |= TTY_QUOTE;
497 #endif
498 }
499 if (clp->c_cc == 0)
500 clp->c_cf = clp->c_cl = (u_char *)0;
501 out:
502 splx(s);
503 return c;
504 }
505
506 /*
507 * Put the chars in the from queue on the end of the to queue.
508 */
509 void
510 catq(struct clist *from, struct clist *to)
511 {
512 int c;
513
514 while ((c = getc(from)) != -1)
515 putc(c, to);
516 }
517