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