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