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