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