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