]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/tty_subr.c
xnu-792.10.96.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/ioctl.h>
60 #include <sys/tty.h>
61 #include <sys/malloc.h>
62
63 #include <machine/spl.h>
64
65 /*
66 * At compile time, choose:
67 * There are two ways the TTY_QUOTE bit can be stored. If QBITS is
68 * defined we allocate an array of bits -- 1/8th as much memory but
69 * setbit(), clrbit(), and isset() take more cpu. If QBITS is
70 * undefined, we just use an array of bytes.
71 *
72 * If TTY_QUOTE functionality isn't required by a line discipline,
73 * it can free c_cq and set it to NULL. This speeds things up,
74 * and also does not use any extra memory. This is useful for (say)
75 * a SLIP line discipline that wants a 32K ring buffer for data
76 * but doesn't need quoting.
77 */
78 #define QBITS
79
80 #ifdef QBITS
81 #define QMEM(n) ((((n)-1)/NBBY)+1)
82 #else
83 #define QMEM(n) (n)
84 #endif
85
86
87 /*
88 * Initialize clists.
89 */
90 void
91 cinit(void)
92 {
93 }
94
95 /*
96 * Initialize a particular clist. Ok, they are really ring buffers,
97 * of the specified length, with/without quoting support.
98 */
99 int
100 clalloc(clp, size, quot)
101 struct clist *clp;
102 int size;
103 int quot;
104 {
105
106 MALLOC_ZONE(clp->c_cs, u_char *, size, M_TTYS, M_WAITOK);
107 if (!clp->c_cs)
108 return (-1);
109 bzero(clp->c_cs, size);
110
111 if(quot) {
112 MALLOC_ZONE(clp->c_cq, u_char *, QMEM(size), M_TTYS, M_WAITOK);
113 if (!clp->c_cq) {
114 FREE_ZONE(clp->c_cs, size, M_TTYS);
115 return (-1);
116 }
117 bzero(clp->c_cs, QMEM(size));
118 } else
119 clp->c_cq = (u_char *)0;
120
121 clp->c_cf = clp->c_cl = (u_char *)0;
122 clp->c_ce = clp->c_cs + size;
123 clp->c_cn = size;
124 clp->c_cc = 0;
125 return (0);
126 }
127
128 void
129 clfree(clp)
130 struct clist *clp;
131 {
132 if(clp->c_cs)
133 FREE_ZONE(clp->c_cs, clp->c_cn, M_TTYS);
134 if(clp->c_cq)
135 FREE_ZONE(clp->c_cq, QMEM(clp->c_cn), M_TTYS);
136 clp->c_cs = clp->c_cq = (u_char *)0;
137 }
138
139
140 /*
141 * Get a character from a clist.
142 */
143 int
144 getc(clp)
145 struct clist *clp;
146 {
147 register int c = -1;
148 int s;
149
150 s = spltty();
151 if (clp->c_cc == 0)
152 goto out;
153
154 c = *clp->c_cf & 0xff;
155 if (clp->c_cq) {
156 #ifdef QBITS
157 if (isset(clp->c_cq, clp->c_cf - clp->c_cs) )
158 c |= TTY_QUOTE;
159 #else
160 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
161 c |= TTY_QUOTE;
162 #endif
163 }
164 if (++clp->c_cf == clp->c_ce)
165 clp->c_cf = clp->c_cs;
166 if (--clp->c_cc == 0)
167 clp->c_cf = clp->c_cl = (u_char *)0;
168 out:
169 splx(s);
170 return c;
171 }
172
173 /*
174 * Copy clist to buffer.
175 * Return number of bytes moved.
176 */
177 int
178 q_to_b(clp, cp, count)
179 struct clist *clp;
180 u_char *cp;
181 int count;
182 {
183 register int cc;
184 u_char *p = cp;
185 int s;
186
187 s = spltty();
188 /* optimize this while loop */
189 while (count > 0 && clp->c_cc > 0) {
190 cc = clp->c_cl - clp->c_cf;
191 if (clp->c_cf >= clp->c_cl)
192 cc = clp->c_ce - clp->c_cf;
193 if (cc > count)
194 cc = count;
195 bcopy(clp->c_cf, p, cc);
196 count -= cc;
197 p += cc;
198 clp->c_cc -= cc;
199 clp->c_cf += cc;
200 if (clp->c_cf == clp->c_ce)
201 clp->c_cf = clp->c_cs;
202 }
203 if (clp->c_cc == 0)
204 clp->c_cf = clp->c_cl = (u_char *)0;
205 splx(s);
206 return p - cp;
207 }
208
209 /*
210 * Return count of contiguous characters in clist.
211 * Stop counting if flag&character is non-null.
212 */
213 int
214 ndqb(clp, flag)
215 struct clist *clp;
216 int flag;
217 {
218 int count = 0;
219 register int i;
220 register int cc;
221 int s;
222
223 s = spltty();
224 if ((cc = clp->c_cc) == 0)
225 goto out;
226
227 if (flag == 0) {
228 count = clp->c_cl - clp->c_cf;
229 if (count <= 0)
230 count = clp->c_ce - clp->c_cf;
231 goto out;
232 }
233
234 i = clp->c_cf - clp->c_cs;
235 if (flag & TTY_QUOTE) {
236 while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) ||
237 isset(clp->c_cq, i))) {
238 count++;
239 if (i == clp->c_cn)
240 break;
241 }
242 } else {
243 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) {
244 count++;
245 if (i == clp->c_cn)
246 break;
247 }
248 }
249 out:
250 splx(s);
251 return count;
252 }
253
254 /*
255 * Flush count bytes from clist.
256 */
257 void
258 ndflush(clp, count)
259 struct clist *clp;
260 int count;
261 {
262 register int cc;
263 int s;
264
265 s = spltty();
266 if (count == clp->c_cc) {
267 clp->c_cc = 0;
268 clp->c_cf = clp->c_cl = (u_char *)0;
269 goto out;
270 }
271 /* optimize this while loop */
272 while (count > 0 && clp->c_cc > 0) {
273 cc = clp->c_cl - clp->c_cf;
274 if (clp->c_cf >= clp->c_cl)
275 cc = clp->c_ce - clp->c_cf;
276 if (cc > count)
277 cc = count;
278 count -= cc;
279 clp->c_cc -= cc;
280 clp->c_cf += cc;
281 if (clp->c_cf == clp->c_ce)
282 clp->c_cf = clp->c_cs;
283 }
284 if (clp->c_cc == 0)
285 clp->c_cf = clp->c_cl = (u_char *)0;
286 out:
287 splx(s);
288 }
289
290 /*
291 * Put a character into the output queue.
292 */
293 int
294 putc(c, clp)
295 int c;
296 struct clist *clp;
297 {
298 register int i;
299 int s;
300
301 s = spltty();
302 if (clp->c_cc == 0) {
303 if (!clp->c_cs) {
304 #if DIAGNOSTIC
305 //printf("putc: required clalloc\n");
306 #endif
307 if(clalloc(clp, 1024, 1)) {
308 out:
309 splx(s);
310 return -1;
311 }
312 }
313 clp->c_cf = clp->c_cl = clp->c_cs;
314 }
315
316 if (clp->c_cc == clp->c_cn)
317 goto out;
318
319 *clp->c_cl = c & 0xff;
320 i = clp->c_cl - clp->c_cs;
321 if (clp->c_cq) {
322 #ifdef QBITS
323 if (c & TTY_QUOTE)
324 setbit(clp->c_cq, i);
325 else
326 clrbit(clp->c_cq, i);
327 #else
328 q = clp->c_cq + i;
329 *q = (c & TTY_QUOTE) ? 1 : 0;
330 #endif
331 }
332 clp->c_cc++;
333 clp->c_cl++;
334 if (clp->c_cl == clp->c_ce)
335 clp->c_cl = clp->c_cs;
336 splx(s);
337 return 0;
338 }
339
340 #ifdef QBITS
341 /*
342 * optimized version of
343 *
344 * for (i = 0; i < len; i++)
345 * clrbit(cp, off + len);
346 */
347 void
348 clrbits(u_char *cp, int off, int len)
349 {
350 int sby, sbi, eby, ebi;
351 register int i;
352 u_char mask;
353
354 if(len==1) {
355 clrbit(cp, off);
356 return;
357 }
358
359 sby = off / NBBY;
360 sbi = off % NBBY;
361 eby = (off+len) / NBBY;
362 ebi = (off+len) % NBBY;
363 if (sby == eby) {
364 mask = ((1 << (ebi - sbi)) - 1) << sbi;
365 cp[sby] &= ~mask;
366 } else {
367 mask = (1<<sbi) - 1;
368 cp[sby++] &= mask;
369
370 mask = (1<<ebi) - 1;
371 cp[eby] &= ~mask;
372
373 for (i = sby; i < eby; i++)
374 cp[i] = 0x00;
375 }
376 }
377 #endif
378
379 /*
380 * Copy buffer to clist.
381 * Return number of bytes not transfered.
382 */
383 int
384 b_to_q(const u_char *cp, int count, struct clist *clp)
385 {
386 int cc;
387 const u_char *p = cp;
388 int s;
389
390 if (count <= 0)
391 return 0;
392
393 s = spltty();
394
395 if (clp->c_cc == 0) {
396 if (!clp->c_cs) {
397 #if DIAGNOSTIC
398 printf("b_to_q: required clalloc\n");
399 #endif
400 if(clalloc(clp, 1024, 1))
401 goto out;
402 }
403 clp->c_cf = clp->c_cl = clp->c_cs;
404 }
405
406 if (clp->c_cc == clp->c_cn)
407 goto out;
408
409 /* optimize this while loop */
410 while (count > 0 && clp->c_cc < clp->c_cn) {
411 cc = clp->c_ce - clp->c_cl;
412 if (clp->c_cf > clp->c_cl)
413 cc = clp->c_cf - clp->c_cl;
414 if (cc > count)
415 cc = count;
416 bcopy(p, clp->c_cl, cc);
417 if (clp->c_cq) {
418 #ifdef QBITS
419 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc);
420 #else
421 bzero(clp->c_cl - clp->c_cs + clp->c_cq, cc);
422 #endif
423 }
424 p += cc;
425 count -= cc;
426 clp->c_cc += cc;
427 clp->c_cl += cc;
428 if (clp->c_cl == clp->c_ce)
429 clp->c_cl = clp->c_cs;
430 }
431 out:
432 splx(s);
433 return count;
434 }
435
436 static int cc;
437
438 /*
439 * Given a non-NULL pointer into the clist return the pointer
440 * to the next character in the list or return NULL if no more chars.
441 *
442 * Callers must not allow getc's to happen between firstc's and getc's
443 * so that the pointer becomes invalid. Note that interrupts are NOT
444 * masked.
445 */
446 u_char *
447 nextc(clp, cp, c)
448 struct clist *clp;
449 register u_char *cp;
450 int *c;
451 {
452
453 if (clp->c_cf == cp) {
454 /*
455 * First time initialization.
456 */
457 cc = clp->c_cc;
458 }
459 if (cc == 0 || cp == NULL)
460 return NULL;
461 if (--cc == 0)
462 return NULL;
463 if (++cp == clp->c_ce)
464 cp = clp->c_cs;
465 *c = *cp & 0xff;
466 if (clp->c_cq) {
467 #ifdef QBITS
468 if (isset(clp->c_cq, cp - clp->c_cs))
469 *c |= TTY_QUOTE;
470 #else
471 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
472 *c |= TTY_QUOTE;
473 #endif
474 }
475 return cp;
476 }
477
478 /*
479 * Given a non-NULL pointer into the clist return the pointer
480 * to the first character in the list or return NULL if no more chars.
481 *
482 * Callers must not allow getc's to happen between firstc's and getc's
483 * so that the pointer becomes invalid. Note that interrupts are NOT
484 * masked.
485 *
486 * *c is set to the NEXT character
487 */
488 u_char *
489 firstc(clp, c)
490 struct clist *clp;
491 int *c;
492 {
493 register u_char *cp;
494
495 cc = clp->c_cc;
496 if (cc == 0)
497 return NULL;
498 cp = clp->c_cf;
499 *c = *cp & 0xff;
500 if(clp->c_cq) {
501 #ifdef QBITS
502 if (isset(clp->c_cq, cp - clp->c_cs))
503 *c |= TTY_QUOTE;
504 #else
505 if (*(cp - clp->c_cs + clp->c_cq))
506 *c |= TTY_QUOTE;
507 #endif
508 }
509 return clp->c_cf;
510 }
511
512 /*
513 * Remove the last character in the clist and return it.
514 */
515 int
516 unputc(clp)
517 struct clist *clp;
518 {
519 unsigned int c = -1;
520 int s;
521
522 s = spltty();
523 if (clp->c_cc == 0)
524 goto out;
525
526 if (clp->c_cl == clp->c_cs)
527 clp->c_cl = clp->c_ce - 1;
528 else
529 --clp->c_cl;
530 clp->c_cc--;
531
532 c = *clp->c_cl & 0xff;
533 if (clp->c_cq) {
534 #ifdef QBITS
535 if (isset(clp->c_cq, clp->c_cl - clp->c_cs))
536 c |= TTY_QUOTE;
537 #else
538 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
539 c |= TTY_QUOTE;
540 #endif
541 }
542 if (clp->c_cc == 0)
543 clp->c_cf = clp->c_cl = (u_char *)0;
544 out:
545 splx(s);
546 return c;
547 }
548
549 /*
550 * Put the chars in the from queue on the end of the to queue.
551 */
552 void
553 catq(from, to)
554 struct clist *from, *to;
555 {
556 int c;
557
558 while ((c = getc(from)) != -1)
559 putc(c, to);
560 }
561
562 #endif /* NeXT */