1 /* $OpenBSD: tty_subr.c,v 1.21 2009/07/19 08:16:06 blambert 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 mask = (1<<ebi) - 1; 308 cp[eby] &= ~mask; 309 310 for (i = sby; i < eby; i++) 311 cp[i] = 0x00; 312 } 313 } 314 315 /* 316 * Copy buffer to clist. 317 * Return number of bytes not transferred. 318 */ 319 int 320 b_to_q(u_char *cp, int count, struct clist *clp) 321 { 322 int cc; 323 u_char *p = cp; 324 int s; 325 326 if (count <= 0) 327 return 0; 328 329 s = spltty(); 330 if (clp->c_cc == clp->c_cn) 331 goto out; 332 333 if (clp->c_cc == 0) { 334 if (!clp->c_cs) { 335 #if defined(DIAGNOSTIC) || 1 336 printf("b_to_q: required clalloc\n"); 337 #endif 338 clalloc(clp, 1024, 1); 339 } 340 clp->c_cf = clp->c_cl = clp->c_cs; 341 } 342 343 /* optimize this while loop */ 344 while (count > 0 && clp->c_cc < clp->c_cn) { 345 cc = clp->c_ce - clp->c_cl; 346 if (clp->c_cf > clp->c_cl) 347 cc = clp->c_cf - clp->c_cl; 348 if (cc > count) 349 cc = count; 350 bcopy(p, clp->c_cl, cc); 351 if (clp->c_cq) 352 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc); 353 p += cc; 354 count -= cc; 355 clp->c_cc += cc; 356 clp->c_cl += cc; 357 if (clp->c_cl == clp->c_ce) 358 clp->c_cl = clp->c_cs; 359 } 360 out: 361 splx(s); 362 return count; 363 } 364 365 static int cc; 366 367 /* 368 * Given a non-NULL pointer into the clist return the pointer 369 * to the next character in the list or return NULL if no more chars. 370 * 371 * Callers must not allow getc's to happen between firstc's and getc's 372 * so that the pointer becomes invalid. Note that interrupts are NOT 373 * masked. 374 */ 375 u_char * 376 nextc(struct clist *clp, u_char *cp, int *c) 377 { 378 379 if (clp->c_cf == cp) { 380 /* 381 * First time initialization. 382 */ 383 cc = clp->c_cc; 384 } 385 if (cc == 0 || cp == NULL) 386 return NULL; 387 if (--cc == 0) 388 return NULL; 389 if (++cp == clp->c_ce) 390 cp = clp->c_cs; 391 *c = *cp & 0xff; 392 if (clp->c_cq) { 393 if (isset(clp->c_cq, cp - clp->c_cs)) 394 *c |= TTY_QUOTE; 395 } 396 return cp; 397 } 398 399 /* 400 * Given a non-NULL pointer into the clist return the pointer 401 * to the first character in the list or return NULL if no more chars. 402 * 403 * Callers must not allow getc's to happen between firstc's and getc's 404 * so that the pointer becomes invalid. Note that interrupts are NOT 405 * masked. 406 * 407 * *c is set to the NEXT character 408 */ 409 u_char * 410 firstc(struct clist *clp, int *c) 411 { 412 u_char *cp; 413 414 cc = clp->c_cc; 415 if (cc == 0) 416 return NULL; 417 cp = clp->c_cf; 418 *c = *cp & 0xff; 419 if (clp->c_cq) { 420 if (isset(clp->c_cq, cp - clp->c_cs)) 421 *c |= TTY_QUOTE; 422 } 423 return clp->c_cf; 424 } 425 426 /* 427 * Remove the last character in the clist and return it. 428 */ 429 int 430 unputc(struct clist *clp) 431 { 432 unsigned int c = -1; 433 int s; 434 435 s = spltty(); 436 if (clp->c_cc == 0) 437 goto out; 438 439 if (clp->c_cl == clp->c_cs) 440 clp->c_cl = clp->c_ce - 1; 441 else 442 --clp->c_cl; 443 clp->c_cc--; 444 445 c = *clp->c_cl & 0xff; 446 if (clp->c_cq) { 447 if (isset(clp->c_cq, clp->c_cl - clp->c_cs)) 448 c |= TTY_QUOTE; 449 } 450 if (clp->c_cc == 0) 451 clp->c_cf = clp->c_cl = (u_char *)0; 452 out: 453 splx(s); 454 return c; 455 } 456 457 /* 458 * Put the chars in the from queue on the end of the to queue. 459 */ 460 void 461 catq(struct clist *from, struct clist *to) 462 { 463 int c; 464 int s; 465 466 s = spltty(); 467 if (from->c_cc == 0) { /* nothing to move */ 468 splx(s); 469 return; 470 } 471 472 /* 473 * if `to' queue is empty and the queues are the same max size, 474 * it is more efficient to just swap the clist structures. 475 */ 476 if (to->c_cc == 0 && from->c_cn == to->c_cn) { 477 struct clist tmp; 478 479 tmp = *from; 480 *from = *to; 481 *to = tmp; 482 splx(s); 483 return; 484 } 485 splx(s); 486 487 while ((c = getc(from)) != -1) 488 putc(c, to); 489 } 490