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