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