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