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