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