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