1 /*- 2 * Copyright (c) 1982, 1986, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * %sccs.include.proprietary.c% 11 * 12 * @(#)tty_subr.c 8.3 (Berkeley) 01/21/94 13 */ 14 15 #include <sys/param.h> 16 #include <sys/systm.h> 17 #include <sys/buf.h> 18 #include <sys/ioctl.h> 19 #include <sys/proc.h> 20 #include <sys/tty.h> 21 #include <sys/clist.h> 22 23 char cwaiting; 24 struct cblock *cfree, *cfreelist; 25 int cfreecount, nclist; 26 27 #define setquote(cp) \ 28 setbit(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \ 29 (int)(cp)&CROUND) 30 #define isquote(cp) \ 31 isset(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \ 32 (int)(cp)&CROUND) 33 #define cbptr(x) ((struct cblock *)(x)) 34 35 /* 36 * Initialize clist by freeing all character blocks. 37 */ 38 void 39 clist_init() 40 { 41 register int ccp; 42 register struct cblock *cp; 43 44 ccp = (int) cfree; 45 ccp = (ccp + CROUND) & ~CROUND; 46 for(cp = (struct cblock *) ccp; cp < &cfree[nclist - 1]; cp++) { 47 cp->c_next = cfreelist; 48 cfreelist = cp; 49 cfreecount += CBSIZE; 50 } 51 } 52 53 /* 54 * Character list get/put 55 */ 56 getc(p) 57 register struct clist *p; 58 { 59 register struct cblock *bp; 60 register int c, s; 61 62 s = spltty(); 63 if (p->c_cc <= 0) { 64 c = -1; 65 p->c_cc = 0; 66 p->c_cf = p->c_cl = NULL; 67 } else { 68 c = *p->c_cf & 0377; 69 if (isquote(p->c_cf)) 70 c |= TTY_QUOTE; 71 p->c_cf++; 72 if (--p->c_cc<=0) { 73 bp = cbptr(p->c_cf-1); 74 bp = cbptr((int)bp & ~CROUND); 75 p->c_cf = NULL; 76 p->c_cl = NULL; 77 bp->c_next = cfreelist; 78 cfreelist = bp; 79 cfreecount += CBSIZE; 80 if (cwaiting) { 81 wakeup(&cwaiting); 82 cwaiting = 0; 83 } 84 } else if (((int)p->c_cf & CROUND) == 0){ 85 bp = cbptr(p->c_cf); 86 bp--; 87 p->c_cf = bp->c_next->c_info; 88 bp->c_next = cfreelist; 89 cfreelist = bp; 90 cfreecount += CBSIZE; 91 if (cwaiting) { 92 wakeup(&cwaiting); 93 cwaiting = 0; 94 } 95 } 96 } 97 splx(s); 98 return (c); 99 } 100 101 /* 102 * copy clist to buffer. 103 * return number of bytes moved. 104 */ 105 q_to_b(q, cp, cc) 106 register struct clist *q; 107 register char *cp; 108 int cc; 109 { 110 register struct cblock *bp; 111 register int s, nc; 112 char *acp; 113 114 if (cc <= 0) 115 return (0); 116 s = spltty(); 117 if (q->c_cc <= 0) { 118 q->c_cc = 0; 119 q->c_cf = q->c_cl = NULL; 120 splx(s); 121 return (0); 122 } 123 acp = cp; 124 125 while (cc) { 126 nc = sizeof (struct cblock) - ((int)q->c_cf & CROUND); 127 nc = min(nc, cc); 128 nc = min(nc, q->c_cc); 129 (void) bcopy(q->c_cf, cp, (unsigned)nc); 130 q->c_cf += nc; 131 q->c_cc -= nc; 132 cc -= nc; 133 cp += nc; 134 if (q->c_cc <= 0) { 135 bp = cbptr(q->c_cf - 1); 136 bp = cbptr((int)bp & ~CROUND); 137 q->c_cf = q->c_cl = NULL; 138 bp->c_next = cfreelist; 139 cfreelist = bp; 140 cfreecount += CBSIZE; 141 if (cwaiting) { 142 wakeup(&cwaiting); 143 cwaiting = 0; 144 } 145 break; 146 } 147 if (((int)q->c_cf & CROUND) == 0) { 148 bp = cbptr(q->c_cf); 149 bp--; 150 q->c_cf = bp->c_next->c_info; 151 bp->c_next = cfreelist; 152 cfreelist = bp; 153 cfreecount += CBSIZE; 154 if (cwaiting) { 155 wakeup(&cwaiting); 156 cwaiting = 0; 157 } 158 } 159 } 160 splx(s); 161 return (cp-acp); 162 } 163 164 /* 165 * Return count of contiguous characters 166 * in clist starting at q->c_cf. 167 * Stop counting if flag&character is non-null. 168 */ 169 ndqb(q, flag) 170 register struct clist *q; 171 int flag; 172 { 173 register int cc, s; 174 175 s = spltty(); 176 if (q->c_cc <= 0) { 177 cc = -q->c_cc; 178 goto out; 179 } 180 cc = ((int)q->c_cf + CBSIZE) & ~CROUND; 181 cc -= (int)q->c_cf; 182 if (q->c_cc < cc) 183 cc = q->c_cc; 184 if (flag) { 185 register char *p, *end; 186 187 p = q->c_cf; 188 end = p; 189 end += cc; 190 while (p < end) { 191 if (*p & flag) { 192 cc = (int)p; 193 cc -= (int)q->c_cf; 194 break; 195 } 196 p++; 197 } 198 } 199 out: 200 splx(s); 201 return (cc); 202 } 203 204 /* 205 * Flush cc bytes from q. 206 */ 207 void 208 ndflush(q, cc) 209 register struct clist *q; 210 register int cc; 211 { 212 register struct cblock *bp; 213 char *end; 214 int rem, s; 215 216 s = spltty(); 217 if (q->c_cc <= 0) 218 goto out; 219 while (cc>0 && q->c_cc) { 220 bp = cbptr((int)q->c_cf & ~CROUND); 221 if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) { 222 end = q->c_cl; 223 } else { 224 end = (char *)((int)bp + sizeof (struct cblock)); 225 } 226 rem = end - q->c_cf; 227 if (cc >= rem) { 228 cc -= rem; 229 q->c_cc -= rem; 230 q->c_cf = bp->c_next->c_info; 231 bp->c_next = cfreelist; 232 cfreelist = bp; 233 cfreecount += CBSIZE; 234 if (cwaiting) { 235 wakeup(&cwaiting); 236 cwaiting = 0; 237 } 238 } else { 239 q->c_cc -= cc; 240 q->c_cf += cc; 241 if (q->c_cc <= 0) { 242 bp->c_next = cfreelist; 243 cfreelist = bp; 244 cfreecount += CBSIZE; 245 if (cwaiting) { 246 wakeup(&cwaiting); 247 cwaiting = 0; 248 } 249 } 250 break; 251 } 252 } 253 if (q->c_cc <= 0) { 254 q->c_cf = q->c_cl = NULL; 255 q->c_cc = 0; 256 } 257 out: 258 splx(s); 259 } 260 261 262 putc(c, p) 263 int c; 264 register struct clist *p; 265 { 266 register struct cblock *bp; 267 register char *cp; 268 register int s; 269 270 s = spltty(); 271 if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { /* no cblocks yet */ 272 if ((bp = cfreelist) == NULL) { 273 splx(s); 274 return (-1); 275 } 276 cfreelist = bp->c_next; 277 cfreecount -= CBSIZE; 278 bp->c_next = NULL; 279 bzero(bp->c_quote, CBQSIZE); 280 p->c_cf = cp = bp->c_info; 281 } else if (((int)cp & CROUND) == 0) { 282 bp = cbptr(cp) - 1; /* pointer arith */ 283 if ((bp->c_next = cfreelist) == NULL) { 284 splx(s); 285 return (-1); 286 } 287 bp = bp->c_next; 288 cfreelist = bp->c_next; 289 cfreecount -= CBSIZE; 290 bp->c_next = NULL; 291 cp = bp->c_info; 292 } 293 if (c&TTY_QUOTE) 294 setquote(cp); 295 *cp++ = c; 296 p->c_cc++; 297 p->c_cl = cp; 298 splx(s); 299 return (0); 300 } 301 302 /* 303 * copy buffer to clist. 304 * return number of bytes not transfered. 305 */ 306 b_to_q(cp, cc, q) 307 register char *cp; 308 struct clist *q; 309 register int cc; 310 { 311 register char *cq; 312 register struct cblock *bp; 313 register int s, nc; 314 int acc; 315 316 if (cc <= 0) 317 return (0); 318 acc = cc; 319 s = spltty(); 320 if ((cq = q->c_cl) == NULL || q->c_cc < 0) { 321 if ((bp = cfreelist) == NULL) 322 goto out; 323 cfreelist = bp->c_next; 324 cfreecount -= CBSIZE; 325 bzero(bp->c_quote, CBQSIZE); 326 bp->c_next = NULL; 327 q->c_cf = cq = bp->c_info; 328 } 329 330 while (cc) { 331 if (((int)cq & CROUND) == 0) { 332 bp = cbptr(cq) - 1; 333 if ((bp->c_next = cfreelist) == NULL) 334 goto out; 335 bp = bp->c_next; 336 cfreelist = bp->c_next; 337 cfreecount -= CBSIZE; 338 bzero(bp->c_quote, CBQSIZE); 339 bp->c_next = NULL; 340 cq = bp->c_info; 341 } 342 nc = min(cc, sizeof (struct cblock) - ((int)cq & CROUND)); 343 (void) bcopy(cp, cq, (unsigned)nc); 344 cp += nc; 345 cq += nc; 346 cc -= nc; 347 } 348 out: 349 q->c_cl = cq; 350 q->c_cc += acc - cc; 351 splx(s); 352 return (cc); 353 } 354 355 /* 356 * Given a non-NULL pointter into the list (like c_cf which 357 * always points to a real character if non-NULL) return the pointer 358 * to the next character in the list or return NULL if no more chars. 359 * 360 * Callers must not allow getc's to happen between nextc's so that the 361 * pointer becomes invalid. Note that interrupts are NOT masked. 362 */ 363 char * 364 nextc(p, cp, c) 365 register struct clist *p; 366 register char *cp; 367 register int *c; 368 { 369 370 if (p->c_cc && ++cp != p->c_cl) { 371 if (((int)cp & CROUND) == 0) { 372 cp = (cbptr(cp))[-1].c_next->c_info; 373 } 374 *c = *cp; 375 if (isquote(cp)) 376 *c |= TTY_QUOTE; 377 return (cp); 378 } 379 return (0); 380 } 381 382 /* 383 * Remove the last character in the list and return it. 384 */ 385 unputc(p) 386 register struct clist *p; 387 { 388 register struct cblock *bp; 389 register int c, s; 390 struct cblock *obp; 391 392 s = spltty(); 393 if (p->c_cc <= 0) 394 c = -1; 395 else { 396 c = *--p->c_cl; 397 if (isquote(p->c_cl)) 398 c |= TTY_QUOTE; 399 if (--p->c_cc <= 0) { 400 bp = cbptr(p->c_cl); 401 bp = cbptr((int)bp & ~CROUND); 402 p->c_cl = p->c_cf = NULL; 403 bp->c_next = cfreelist; 404 cfreelist = bp; 405 cfreecount += CBSIZE; 406 } else if (p->c_cl == (cbptr((int)p->c_cl & ~CROUND))->c_info) { 407 p->c_cl = (char *)((int)p->c_cl & ~CROUND); 408 409 bp = cbptr(p->c_cf); 410 bp = cbptr((int)bp & ~CROUND); 411 while (bp->c_next != cbptr(p->c_cl)) 412 bp = bp->c_next; 413 obp = bp; 414 p->c_cl = (char *)(bp + 1); 415 bp = bp->c_next; 416 bp->c_next = cfreelist; 417 cfreelist = bp; 418 cfreecount += CBSIZE; 419 obp->c_next = NULL; 420 } 421 } 422 splx(s); 423 return (c); 424 } 425 426 /* 427 * Put the chars in the from que 428 * on the end of the to que. 429 */ 430 void 431 catq(from, to) 432 struct clist *from, *to; 433 { 434 #ifdef notdef 435 char bbuf[CBSIZE*4]; 436 #endif 437 register int s, c; 438 439 s = spltty(); 440 if (to->c_cc == 0) { 441 *to = *from; 442 from->c_cc = 0; 443 from->c_cf = NULL; 444 from->c_cl = NULL; 445 splx(s); 446 return; 447 } 448 splx(s); 449 #ifdef notdef 450 while (from->c_cc > 0) { 451 c = q_to_b(from, bbuf, sizeof bbuf); 452 (void) b_to_q(bbuf, c, to); 453 } 454 #endif 455 /* XXX - FIX */ 456 while ((c = getc(from)) >= 0) 457 putc(c, to); 458 } 459 460 #ifdef unneeded 461 /* 462 * Integer (short) get/put using clists. 463 */ 464 typedef u_short word_t; 465 466 getw(p) 467 register struct clist *p; 468 { 469 register int s, c; 470 register struct cblock *bp; 471 472 if (p->c_cc <= 1) 473 return(-1); 474 if (p->c_cc & 01) { 475 c = getc(p); 476 #if BYTE_ORDER == LITTLE_ENDIAN 477 return (c | (getc(p)<<8)); 478 #else 479 return (getc(p) | (c<<8)); 480 #endif 481 } 482 s = spltty(); 483 #if BYTE_ORDER == LITTLE_ENDIAN 484 c = (((u_char *)p->c_cf)[0] << 8) | ((u_char *)p->c_cf)[1]; 485 #else 486 c = (((u_char *)p->c_cf)[1] << 8) | ((u_char *)p->c_cf)[0]; 487 #endif 488 p->c_cf += sizeof (word_t); 489 p->c_cc -= sizeof (word_t); 490 if (p->c_cc <= 0) { 491 bp = cbptr(p->c_cf-1); 492 bp = cbptr((int)bp & ~CROUND); 493 p->c_cf = NULL; 494 p->c_cl = NULL; 495 bp->c_next = cfreelist; 496 cfreelist = bp; 497 cfreecount += CBSIZE; 498 if (cwaiting) { 499 wakeup(&cwaiting); 500 cwaiting = 0; 501 } 502 } else if (((int)p->c_cf & CROUND) == 0) { 503 bp = cbptr(p->c_cf); 504 bp--; 505 p->c_cf = bp->c_next->c_info; 506 bp->c_next = cfreelist; 507 cfreelist = bp; 508 cfreecount += CBSIZE; 509 if (cwaiting) { 510 wakeup(&cwaiting); 511 cwaiting = 0; 512 } 513 } 514 splx(s); 515 return (c); 516 } 517 518 putw(c, p) 519 register struct clist *p; 520 word_t c; 521 { 522 register int s; 523 register struct cblock *bp; 524 register char *cp; 525 526 s = spltty(); 527 if (cfreelist==NULL) { 528 splx(s); 529 return(-1); 530 } 531 if (p->c_cc & 01) { 532 #if BYTE_ORDER == LITTLE_ENDIAN 533 (void) putc(c, p); 534 (void) putc(c>>8, p); 535 #else 536 (void) putc(c>>8, p); 537 (void) putc(c, p); 538 #endif 539 } else { 540 if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { 541 if ((bp = cfreelist) == NULL) { 542 splx(s); 543 return (-1); 544 } 545 cfreelist = bp->c_next; 546 cfreecount -= CBSIZE; 547 bp->c_next = NULL; 548 p->c_cf = cp = bp->c_info; 549 } else if (((int)cp & CROUND) == 0) { 550 bp = cbptr(cp) - 1; 551 if ((bp->c_next = cfreelist) == NULL) { 552 splx(s); 553 return (-1); 554 } 555 bp = bp->c_next; 556 cfreelist = bp->c_next; 557 cfreecount -= CBSIZE; 558 bp->c_next = NULL; 559 cp = bp->c_info; 560 } 561 #if defined(vax) 562 *(word_t *)cp = c; 563 #else 564 ((u_char *)cp)[0] = c>>8; 565 ((u_char *)cp)[1] = c; 566 #endif 567 p->c_cl = cp + sizeof (word_t); 568 p->c_cc += sizeof (word_t); 569 } 570 splx(s); 571 return (0); 572 } 573 #endif /* unneeded */ 574