]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/tty_subr.c
xnu-344.21.73.tar.gz
[apple/xnu.git] / bsd / kern / tty_subr.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
d7e50217 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
d7e50217
A
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
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
d7e50217
A
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.
1c79356b
A
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 */
94void
95cinit()
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 */
103int
104clalloc(clp, size, quot)
105 struct clist *clp;
106 int size;
107 int quot;
108{
109
0b4e3aa0 110 MALLOC_ZONE(clp->c_cs, u_char *, size, M_TTYS, M_WAITOK);
1c79356b
A
111 if (!clp->c_cs)
112 return (-1);
113 bzero(clp->c_cs, size);
114
115 if(quot) {
0b4e3aa0 116 MALLOC_ZONE(clp->c_cq, u_char *, QMEM(size), M_TTYS, M_WAITOK);
1c79356b 117 if (!clp->c_cq) {
0b4e3aa0 118 FREE_ZONE(clp->c_cs, size, M_TTYS);
1c79356b
A
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
132void
133clfree(clp)
134 struct clist *clp;
135{
136 if(clp->c_cs)
0b4e3aa0 137 FREE_ZONE(clp->c_cs, clp->c_cn, M_TTYS);
1c79356b 138 if(clp->c_cq)
0b4e3aa0 139 FREE_ZONE(clp->c_cq, QMEM(clp->c_cn), M_TTYS);
1c79356b
A
140 clp->c_cs = clp->c_cq = (u_char *)0;
141}
142
143
144/*
145 * Get a character from a clist.
146 */
147int
148getc(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;
172out:
173 splx(s);
174 return c;
175}
176
177/*
178 * Copy clist to buffer.
179 * Return number of bytes moved.
180 */
181int
182q_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 */
217int
218ndqb(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 }
253out:
254 splx(s);
255 return count;
256}
257
258/*
259 * Flush count bytes from clist.
260 */
261void
262ndflush(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;
290out:
291 splx(s);
292}
293
294/*
295 * Put a character into the output queue.
296 */
297int
298putc(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)) {
312out:
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 */
351void
352clrbits(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 */
390int
391b_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 }
441out:
442 splx(s);
443 return count;
444}
445
446static 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 */
456u_char *
457nextc(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 */
498u_char *
499firstc(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 */
525int
526unputc(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;
554out:
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 */
562void
563catq(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 */