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