]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/kern/tty_subr.c
xnu-792.12.6.tar.gz
[apple/xnu.git] / bsd / kern / tty_subr.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2006 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 */
98void
99cinit(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 */
107int
108clalloc(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
136void
137clfree(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 */
151int
152getc(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;
176out:
177 splx(s);
178 return c;
179}
180
181/*
182 * Copy clist to buffer.
183 * Return number of bytes moved.
184 */
185int
186q_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 */
221int
222ndqb(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 }
257out:
258 splx(s);
259 return count;
260}
261
262/*
263 * Flush count bytes from clist.
264 */
265void
266ndflush(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;
294out:
295 splx(s);
296}
297
298/*
299 * Put a character into the output queue.
300 */
301int
302putc(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)) {
316out:
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 */
355void
356clrbits(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 */
391int
392b_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 }
439out:
440 splx(s);
441 return count;
442}
443
444static 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 */
454u_char *
455nextc(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 */
496u_char *
497firstc(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 */
523int
524unputc(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;
552out:
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 */
560void
561catq(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 */