1 /* $NetBSD: tty_subr.c,v 1.22 2001/12/27 02:27:50 ad Exp $ */ 2 3 /* 4 * Copyright (c) 1993, 1994 Theo de Raadt 5 * All rights reserved. 6 * 7 * Per Lindqvist <pgd@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/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: tty_subr.c,v 1.22 2001/12/27 02:27:50 ad Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/buf.h> 42 #include <sys/ioctl.h> 43 #include <sys/tty.h> 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 clp->c_cs = malloc(size, M_TTYS, M_WAITOK); 92 if (!clp->c_cs) 93 return (-1); 94 memset(clp->c_cs, 0, size); 95 96 if(quot) { 97 clp->c_cq = malloc(QMEM(size), M_TTYS, M_WAITOK); 98 if (!clp->c_cq) { 99 free(clp->c_cs, M_TTYS); 100 return (-1); 101 } 102 memset(clp->c_cq, 0, 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 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 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 memcpy(p, clp->c_cf, 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 int i; 205 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 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 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 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 int cc; 378 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 memcpy(clp->c_cl, p, cc); 407 if (clp->c_cq) { 408 #ifdef QBITS 409 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc); 410 #else 411 memset(clp->c_cl - clp->c_cs + clp->c_cq, 0, 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 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 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