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