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