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