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