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