tty_subr.c revision 1.31 1 /* $NetBSD: tty_subr.c,v 1.31 2007/11/19 18:51:52 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.31 2007/11/19 18:51:52 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 return (0);
98 }
99
100 void
101 clfree(struct clist *clp)
102 {
103 if(clp->c_cs)
104 free(clp->c_cs, M_TTYS);
105 if(clp->c_cq)
106 free(clp->c_cq, M_TTYS);
107 clp->c_cs = clp->c_cq = (u_char *)0;
108 cv_destroy(&clp->c_cv);
109 }
110
111 void
112 clwakeup(struct clist *clp)
113 {
114
115 cv_broadcast(&clp->c_cv);
116 }
117
118 /*
119 * Get a character from a clist.
120 */
121 int
122 getc(struct clist *clp)
123 {
124 int c = -1;
125 int s;
126
127 s = spltty();
128 if (clp->c_cc == 0)
129 goto out;
130
131 c = *clp->c_cf & 0xff;
132 if (clp->c_cq) {
133 #ifdef QBITS
134 if (isset(clp->c_cq, clp->c_cf - clp->c_cs) )
135 c |= TTY_QUOTE;
136 #else
137 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
138 c |= TTY_QUOTE;
139 #endif
140 }
141 if (++clp->c_cf == clp->c_ce)
142 clp->c_cf = clp->c_cs;
143 if (--clp->c_cc == 0)
144 clp->c_cf = clp->c_cl = (u_char *)0;
145 out:
146 splx(s);
147 return c;
148 }
149
150 /*
151 * Copy clist to buffer.
152 * Return number of bytes moved.
153 */
154 int
155 q_to_b(struct clist *clp, u_char *cp, int count)
156 {
157 int cc;
158 u_char *p = cp;
159 int s;
160
161 s = spltty();
162 /* optimize this while loop */
163 while (count > 0 && clp->c_cc > 0) {
164 cc = clp->c_cl - clp->c_cf;
165 if (clp->c_cf >= clp->c_cl)
166 cc = clp->c_ce - clp->c_cf;
167 if (cc > count)
168 cc = count;
169 memcpy(p, clp->c_cf, cc);
170 count -= cc;
171 p += cc;
172 clp->c_cc -= cc;
173 clp->c_cf += cc;
174 if (clp->c_cf == clp->c_ce)
175 clp->c_cf = clp->c_cs;
176 }
177 if (clp->c_cc == 0)
178 clp->c_cf = clp->c_cl = (u_char *)0;
179 splx(s);
180 return p - cp;
181 }
182
183 /*
184 * Return count of contiguous characters in clist.
185 * Stop counting if flag&character is non-null.
186 */
187 int
188 ndqb(struct clist *clp, int flag)
189 {
190 int count = 0;
191 int i;
192 int cc;
193 int s;
194
195 s = spltty();
196 if ((cc = clp->c_cc) == 0)
197 goto out;
198
199 if (flag == 0) {
200 count = clp->c_cl - clp->c_cf;
201 if (count <= 0)
202 count = clp->c_ce - clp->c_cf;
203 goto out;
204 }
205
206 i = clp->c_cf - clp->c_cs;
207 if (flag & TTY_QUOTE) {
208 while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) ||
209 isset(clp->c_cq, i))) {
210 count++;
211 if (i == clp->c_cn)
212 break;
213 }
214 } else {
215 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) {
216 count++;
217 if (i == clp->c_cn)
218 break;
219 }
220 }
221 out:
222 splx(s);
223 return count;
224 }
225
226 /*
227 * Flush count bytes from clist.
228 */
229 void
230 ndflush(struct clist *clp, int count)
231 {
232 int cc;
233 int s;
234
235 s = spltty();
236 if (count == clp->c_cc) {
237 clp->c_cc = 0;
238 clp->c_cf = clp->c_cl = (u_char *)0;
239 goto out;
240 }
241 /* optimize this while loop */
242 while (count > 0 && clp->c_cc > 0) {
243 cc = clp->c_cl - clp->c_cf;
244 if (clp->c_cf >= clp->c_cl)
245 cc = clp->c_ce - clp->c_cf;
246 if (cc > count)
247 cc = count;
248 count -= cc;
249 clp->c_cc -= cc;
250 clp->c_cf += cc;
251 if (clp->c_cf == clp->c_ce)
252 clp->c_cf = clp->c_cs;
253 }
254 if (clp->c_cc == 0)
255 clp->c_cf = clp->c_cl = (u_char *)0;
256 out:
257 splx(s);
258 }
259
260 /*
261 * Put a character into the output queue.
262 */
263 int
264 putc(int c, struct clist *clp)
265 {
266 int i;
267 int s;
268
269 s = spltty();
270 if (clp->c_cc == clp->c_cn)
271 goto out;
272
273 if (clp->c_cc == 0) {
274 if (!clp->c_cs) {
275 #if defined(DIAGNOSTIC) || 1
276 printf("putc: required clalloc\n");
277 #endif
278 if(clalloc(clp, 1024, 1)) {
279 out:
280 splx(s);
281 return -1;
282 }
283 }
284 clp->c_cf = clp->c_cl = clp->c_cs;
285 }
286
287 *clp->c_cl = c & 0xff;
288 i = clp->c_cl - clp->c_cs;
289 if (clp->c_cq) {
290 #ifdef QBITS
291 if (c & TTY_QUOTE)
292 setbit(clp->c_cq, i);
293 else
294 clrbit(clp->c_cq, i);
295 #else
296 q = clp->c_cq + i;
297 *q = (c & TTY_QUOTE) ? 1 : 0;
298 #endif
299 }
300 clp->c_cc++;
301 clp->c_cl++;
302 if (clp->c_cl == clp->c_ce)
303 clp->c_cl = clp->c_cs;
304 splx(s);
305 return 0;
306 }
307
308 #ifdef QBITS
309 /*
310 * optimized version of
311 *
312 * for (i = 0; i < len; i++)
313 * clrbit(cp, off + len);
314 */
315 static void
316 clrbits(u_char *cp, int off, int len)
317 {
318 int sby, sbi, eby, ebi;
319 int i;
320 u_char mask;
321
322 if(len==1) {
323 clrbit(cp, off);
324 return;
325 }
326
327 sby = off / NBBY;
328 sbi = off % NBBY;
329 eby = (off+len) / NBBY;
330 ebi = (off+len) % NBBY;
331 if (sby == eby) {
332 mask = ((1 << (ebi - sbi)) - 1) << sbi;
333 cp[sby] &= ~mask;
334 } else {
335 mask = (1<<sbi) - 1;
336 cp[sby++] &= mask;
337
338 mask = (1<<ebi) - 1;
339 cp[eby] &= ~mask;
340
341 for (i = sby; i < eby; i++)
342 cp[i] = 0x00;
343 }
344 }
345 #endif
346
347 /*
348 * Copy buffer to clist.
349 * Return number of bytes not transfered.
350 */
351 int
352 b_to_q(const u_char *cp, int count, struct clist *clp)
353 {
354 int cc;
355 const u_char *p = cp;
356 int s;
357
358 if (count <= 0)
359 return 0;
360
361 s = spltty();
362 if (clp->c_cc == clp->c_cn)
363 goto out;
364
365 if (clp->c_cc == 0) {
366 if (!clp->c_cs) {
367 #if defined(DIAGNOSTIC) || 1
368 printf("b_to_q: required clalloc\n");
369 #endif
370 if(clalloc(clp, 1024, 1))
371 goto out;
372 }
373 clp->c_cf = clp->c_cl = clp->c_cs;
374 }
375
376 /* optimize this while loop */
377 while (count > 0 && clp->c_cc < clp->c_cn) {
378 cc = clp->c_ce - clp->c_cl;
379 if (clp->c_cf > clp->c_cl)
380 cc = clp->c_cf - clp->c_cl;
381 if (cc > count)
382 cc = count;
383 memcpy(clp->c_cl, p, cc);
384 if (clp->c_cq) {
385 #ifdef QBITS
386 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc);
387 #else
388 memset(clp->c_cl - clp->c_cs + clp->c_cq, 0, cc);
389 #endif
390 }
391 p += cc;
392 count -= cc;
393 clp->c_cc += cc;
394 clp->c_cl += cc;
395 if (clp->c_cl == clp->c_ce)
396 clp->c_cl = clp->c_cs;
397 }
398 out:
399 splx(s);
400 return count;
401 }
402
403 static int cc;
404
405 /*
406 * Given a non-NULL pointer into the clist return the pointer
407 * to the next character in the list or return NULL if no more chars.
408 *
409 * Callers must not allow getc's to happen between firstc's and getc's
410 * so that the pointer becomes invalid. Note that interrupts are NOT
411 * masked.
412 */
413 u_char *
414 nextc(struct clist *clp, u_char *cp, int *c)
415 {
416
417 if (clp->c_cf == cp) {
418 /*
419 * First time initialization.
420 */
421 cc = clp->c_cc;
422 }
423 if (cc == 0 || cp == NULL)
424 return NULL;
425 if (--cc == 0)
426 return NULL;
427 if (++cp == clp->c_ce)
428 cp = clp->c_cs;
429 *c = *cp & 0xff;
430 if (clp->c_cq) {
431 #ifdef QBITS
432 if (isset(clp->c_cq, cp - clp->c_cs))
433 *c |= TTY_QUOTE;
434 #else
435 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
436 *c |= TTY_QUOTE;
437 #endif
438 }
439 return cp;
440 }
441
442 /*
443 * Given a non-NULL pointer into the clist return the pointer
444 * to the first character in the list or return NULL if no more chars.
445 *
446 * Callers must not allow getc's to happen between firstc's and getc's
447 * so that the pointer becomes invalid. Note that interrupts are NOT
448 * masked.
449 *
450 * *c is set to the NEXT character
451 */
452 u_char *
453 firstc(struct clist *clp, int *c)
454 {
455 u_char *cp;
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(struct clist *clp)
479 {
480 unsigned int c = -1;
481 int s;
482
483 s = spltty();
484 if (clp->c_cc == 0)
485 goto out;
486
487 if (clp->c_cl == clp->c_cs)
488 clp->c_cl = clp->c_ce - 1;
489 else
490 --clp->c_cl;
491 clp->c_cc--;
492
493 c = *clp->c_cl & 0xff;
494 if (clp->c_cq) {
495 #ifdef QBITS
496 if (isset(clp->c_cq, clp->c_cl - clp->c_cs))
497 c |= TTY_QUOTE;
498 #else
499 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
500 c |= TTY_QUOTE;
501 #endif
502 }
503 if (clp->c_cc == 0)
504 clp->c_cf = clp->c_cl = (u_char *)0;
505 out:
506 splx(s);
507 return c;
508 }
509
510 /*
511 * Put the chars in the from queue on the end of the to queue.
512 */
513 void
514 catq(struct clist *from, struct clist *to)
515 {
516 int c;
517
518 while ((c = getc(from)) != -1)
519 putc(c, to);
520 }
521