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