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