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