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