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