123391Smckusick /* 2*29110Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323391Smckusick * All rights reserved. The Berkeley software License Agreement 423391Smckusick * specifies the terms and conditions for redistribution. 523391Smckusick * 6*29110Smckusick * @(#)tty_subr.c 7.1 (Berkeley) 06/05/86 723391Smckusick */ 81892Swnj 917097Sbloom #include "param.h" 1017097Sbloom #include "systm.h" 1117097Sbloom #include "buf.h" 1217576Sbloom #include "ioctl.h" 1317097Sbloom #include "tty.h" 1417097Sbloom #include "clist.h" 1532Sbill 161890Swnj char cwaiting; 171890Swnj 1832Sbill /* 1932Sbill * Character list get/put 2032Sbill */ 2132Sbill getc(p) 2212754Ssam register struct clist *p; 2332Sbill { 2432Sbill register struct cblock *bp; 2532Sbill register int c, s; 2632Sbill 2717542Skarels s = spltty(); 2832Sbill if (p->c_cc <= 0) { 2932Sbill c = -1; 3032Sbill p->c_cc = 0; 3132Sbill p->c_cf = p->c_cl = NULL; 3232Sbill } else { 3332Sbill c = *p->c_cf++ & 0377; 3432Sbill if (--p->c_cc<=0) { 3532Sbill bp = (struct cblock *)(p->c_cf-1); 3626279Skarels bp = (struct cblock *)((int)bp & ~CROUND); 3732Sbill p->c_cf = NULL; 3832Sbill p->c_cl = NULL; 3932Sbill bp->c_next = cfreelist; 4032Sbill cfreelist = bp; 411890Swnj cfreecount += CBSIZE; 421890Swnj if (cwaiting) { 431890Swnj wakeup(&cwaiting); 441890Swnj cwaiting = 0; 451890Swnj } 4632Sbill } else if (((int)p->c_cf & CROUND) == 0){ 4732Sbill bp = (struct cblock *)(p->c_cf); 4832Sbill bp--; 4932Sbill p->c_cf = bp->c_next->c_info; 5032Sbill bp->c_next = cfreelist; 5132Sbill cfreelist = bp; 521890Swnj cfreecount += CBSIZE; 531890Swnj if (cwaiting) { 541890Swnj wakeup(&cwaiting); 551890Swnj cwaiting = 0; 561890Swnj } 5732Sbill } 5832Sbill } 5932Sbill splx(s); 6026279Skarels return (c); 6132Sbill } 6232Sbill 6332Sbill /* 6432Sbill * copy clist to buffer. 6532Sbill * return number of bytes moved. 6632Sbill */ 6732Sbill q_to_b(q, cp, cc) 689761Ssam register struct clist *q; 699761Ssam register char *cp; 7032Sbill { 7132Sbill register struct cblock *bp; 7232Sbill register int s; 7317542Skarels register nc; 7432Sbill char *acp; 7532Sbill 7632Sbill if (cc <= 0) 7726279Skarels return (0); 7817542Skarels s = spltty(); 7932Sbill if (q->c_cc <= 0) { 8032Sbill q->c_cc = 0; 8132Sbill q->c_cf = q->c_cl = NULL; 821890Swnj splx(s); 8326279Skarels return (0); 8432Sbill } 8532Sbill acp = cp; 8632Sbill 8717542Skarels while (cc) { 8826279Skarels nc = sizeof (struct cblock) - ((int)q->c_cf & CROUND); 8917542Skarels nc = MIN(nc, cc); 9017542Skarels nc = MIN(nc, q->c_cc); 9117542Skarels (void) bcopy(q->c_cf, cp, (unsigned)nc); 9217542Skarels q->c_cf += nc; 9317542Skarels q->c_cc -= nc; 9417542Skarels cc -= nc; 9517542Skarels cp += nc; 9617542Skarels if (q->c_cc <= 0) { 9717542Skarels bp = (struct cblock *)(q->c_cf - 1); 9832Sbill bp = (struct cblock *)((int)bp & ~CROUND); 9932Sbill q->c_cf = q->c_cl = NULL; 10032Sbill bp->c_next = cfreelist; 10132Sbill cfreelist = bp; 1021890Swnj cfreecount += CBSIZE; 1031890Swnj if (cwaiting) { 1041890Swnj wakeup(&cwaiting); 1051890Swnj cwaiting = 0; 1061890Swnj } 10732Sbill break; 10832Sbill } 10932Sbill if (((int)q->c_cf & CROUND) == 0) { 11032Sbill bp = (struct cblock *)(q->c_cf); 11132Sbill bp--; 11232Sbill q->c_cf = bp->c_next->c_info; 11332Sbill bp->c_next = cfreelist; 11432Sbill cfreelist = bp; 1151890Swnj cfreecount += CBSIZE; 1161890Swnj if (cwaiting) { 1171890Swnj wakeup(&cwaiting); 1181890Swnj cwaiting = 0; 1191890Swnj } 12032Sbill } 12132Sbill } 12232Sbill splx(s); 12326279Skarels return (cp-acp); 12432Sbill } 12532Sbill 12632Sbill /* 12732Sbill * Return count of contiguous characters 12832Sbill * in clist starting at q->c_cf. 12932Sbill * Stop counting if flag&character is non-null. 13032Sbill */ 13132Sbill ndqb(q, flag) 1329761Ssam register struct clist *q; 13332Sbill { 1349761Ssam register cc; 1359761Ssam int s; 13632Sbill 13717542Skarels s = spltty(); 13832Sbill if (q->c_cc <= 0) { 13932Sbill cc = -q->c_cc; 14032Sbill goto out; 14132Sbill } 14232Sbill cc = ((int)q->c_cf + CBSIZE) & ~CROUND; 14332Sbill cc -= (int)q->c_cf; 14432Sbill if (q->c_cc < cc) 14532Sbill cc = q->c_cc; 14632Sbill if (flag) { 14732Sbill register char *p, *end; 14832Sbill 14932Sbill p = q->c_cf; 15032Sbill end = p; 15132Sbill end += cc; 15232Sbill while (p < end) { 15332Sbill if (*p & flag) { 1541890Swnj cc = (int)p; 1551890Swnj cc -= (int)q->c_cf; 15632Sbill break; 15732Sbill } 15832Sbill p++; 15932Sbill } 16032Sbill } 16132Sbill out: 16232Sbill splx(s); 16326279Skarels return (cc); 16432Sbill } 16532Sbill 16632Sbill /* 1671890Swnj * Flush cc bytes from q. 16832Sbill */ 16932Sbill ndflush(q, cc) 17012754Ssam register struct clist *q; 17112754Ssam register cc; 17232Sbill { 17312754Ssam register struct cblock *bp; 17412754Ssam char *end; 17512754Ssam int rem, s; 17632Sbill 17717542Skarels s = spltty(); 17826279Skarels if (q->c_cc <= 0) 17932Sbill goto out; 1801890Swnj while (cc>0 && q->c_cc) { 1811890Swnj bp = (struct cblock *)((int)q->c_cf & ~CROUND); 1821890Swnj if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) { 1831890Swnj end = q->c_cl; 1841890Swnj } else { 1851890Swnj end = (char *)((int)bp + sizeof (struct cblock)); 1861890Swnj } 1871890Swnj rem = end - q->c_cf; 1881890Swnj if (cc >= rem) { 1891890Swnj cc -= rem; 1901890Swnj q->c_cc -= rem; 19132Sbill q->c_cf = bp->c_next->c_info; 1921890Swnj bp->c_next = cfreelist; 1931890Swnj cfreelist = bp; 1941890Swnj cfreecount += CBSIZE; 1951890Swnj if (cwaiting) { 1961890Swnj wakeup(&cwaiting); 1971890Swnj cwaiting = 0; 1981890Swnj } 19932Sbill } else { 2001890Swnj q->c_cc -= cc; 2011890Swnj q->c_cf += cc; 2021890Swnj if (q->c_cc <= 0) { 2031890Swnj bp->c_next = cfreelist; 2041890Swnj cfreelist = bp; 2051890Swnj cfreecount += CBSIZE; 2061890Swnj if (cwaiting) { 2071890Swnj wakeup(&cwaiting); 2081890Swnj cwaiting = 0; 2091890Swnj } 2101890Swnj } 2111890Swnj break; 21232Sbill } 2131890Swnj } 2141890Swnj if (q->c_cc <= 0) { 21532Sbill q->c_cf = q->c_cl = NULL; 2161890Swnj q->c_cc = 0; 21732Sbill } 21832Sbill out: 21932Sbill splx(s); 22032Sbill } 221172Sbill 2221890Swnj 22332Sbill putc(c, p) 22412754Ssam register struct clist *p; 22532Sbill { 22632Sbill register struct cblock *bp; 22732Sbill register char *cp; 22832Sbill register s; 22932Sbill 23017542Skarels s = spltty(); 23132Sbill if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { 23232Sbill if ((bp = cfreelist) == NULL) { 23332Sbill splx(s); 23426279Skarels return (-1); 23532Sbill } 23632Sbill cfreelist = bp->c_next; 2371890Swnj cfreecount -= CBSIZE; 23832Sbill bp->c_next = NULL; 23932Sbill p->c_cf = cp = bp->c_info; 24032Sbill } else if (((int)cp & CROUND) == 0) { 24132Sbill bp = (struct cblock *)cp - 1; 24232Sbill if ((bp->c_next = cfreelist) == NULL) { 24332Sbill splx(s); 24426279Skarels return (-1); 24532Sbill } 24632Sbill bp = bp->c_next; 24732Sbill cfreelist = bp->c_next; 2481890Swnj cfreecount -= CBSIZE; 24932Sbill bp->c_next = NULL; 25032Sbill cp = bp->c_info; 25132Sbill } 25232Sbill *cp++ = c; 25332Sbill p->c_cc++; 25432Sbill p->c_cl = cp; 25532Sbill splx(s); 25626279Skarels return (0); 25732Sbill } 25832Sbill 25932Sbill /* 26032Sbill * copy buffer to clist. 26132Sbill * return number of bytes not transfered. 26232Sbill */ 26332Sbill b_to_q(cp, cc, q) 26412754Ssam register char *cp; 26512754Ssam struct clist *q; 26612754Ssam register int cc; 26732Sbill { 26832Sbill register char *cq; 26932Sbill register struct cblock *bp; 27017542Skarels register s, nc; 27117542Skarels int acc; 27232Sbill 27332Sbill if (cc <= 0) 27426279Skarels return (0); 27517542Skarels acc = cc; 27617542Skarels s = spltty(); 27717542Skarels if ((cq = q->c_cl) == NULL || q->c_cc < 0) { 27817542Skarels if ((bp = cfreelist) == NULL) 27917542Skarels goto out; 28017542Skarels cfreelist = bp->c_next; 28117542Skarels cfreecount -= CBSIZE; 28217542Skarels bp->c_next = NULL; 28317542Skarels q->c_cf = cq = bp->c_info; 28417542Skarels } 28517542Skarels 28617542Skarels while (cc) { 28732Sbill if (((int)cq & CROUND) == 0) { 28826279Skarels bp = (struct cblock *)cq - 1; 28917542Skarels if ((bp->c_next = cfreelist) == NULL) 29017542Skarels goto out; 29132Sbill bp = bp->c_next; 29232Sbill cfreelist = bp->c_next; 2931890Swnj cfreecount -= CBSIZE; 29432Sbill bp->c_next = NULL; 29517542Skarels cq = bp->c_info; 29632Sbill } 29726279Skarels nc = MIN(cc, sizeof (struct cblock) - ((int)cq & CROUND)); 29817542Skarels (void) bcopy(cp, cq, (unsigned)nc); 29917542Skarels cp += nc; 30017542Skarels cq += nc; 30117542Skarels cc -= nc; 30232Sbill } 30317542Skarels out: 30417542Skarels q->c_cl = cq; 30517542Skarels q->c_cc += acc - cc; 30617542Skarels splx(s); 30717368Ssam return (cc); 30832Sbill } 30932Sbill 31032Sbill /* 311172Sbill * Given a non-NULL pointter into the list (like c_cf which 312172Sbill * always points to a real character if non-NULL) return the pointer 313172Sbill * to the next character in the list or return NULL if no more chars. 314172Sbill * 315172Sbill * Callers must not allow getc's to happen between nextc's so that the 316172Sbill * pointer becomes invalid. Note that interrupts are NOT masked. 317172Sbill */ 318172Sbill char * 319172Sbill nextc(p, cp) 32012754Ssam register struct clist *p; 32112754Ssam register char *cp; 322172Sbill { 323172Sbill 324172Sbill if (p->c_cc && ++cp != p->c_cl) { 325172Sbill if (((int)cp & CROUND) == 0) 326172Sbill return (((struct cblock *)cp)[-1].c_next->c_info); 327172Sbill return (cp); 328172Sbill } 329172Sbill return (0); 330172Sbill } 331172Sbill 332172Sbill /* 333172Sbill * Remove the last character in the list and return it. 334172Sbill */ 335172Sbill unputc(p) 33612754Ssam register struct clist *p; 337172Sbill { 338172Sbill register struct cblock *bp; 339172Sbill register int c, s; 340172Sbill struct cblock *obp; 341172Sbill 34217542Skarels s = spltty(); 343172Sbill if (p->c_cc <= 0) 344172Sbill c = -1; 345172Sbill else { 346172Sbill c = *--p->c_cl; 347172Sbill if (--p->c_cc <= 0) { 348172Sbill bp = (struct cblock *)p->c_cl; 349172Sbill bp = (struct cblock *)((int)bp & ~CROUND); 350172Sbill p->c_cl = p->c_cf = NULL; 351172Sbill bp->c_next = cfreelist; 352172Sbill cfreelist = bp; 3531890Swnj cfreecount += CBSIZE; 354172Sbill } else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) { 355172Sbill p->c_cl = (char *)((int)p->c_cl & ~CROUND); 356172Sbill bp = (struct cblock *)p->c_cf; 357172Sbill bp = (struct cblock *)((int)bp & ~CROUND); 358172Sbill while (bp->c_next != (struct cblock *)p->c_cl) 359172Sbill bp = bp->c_next; 360172Sbill obp = bp; 361172Sbill p->c_cl = (char *)(bp + 1); 362172Sbill bp = bp->c_next; 363172Sbill bp->c_next = cfreelist; 364172Sbill cfreelist = bp; 3651890Swnj cfreecount += CBSIZE; 366172Sbill obp->c_next = NULL; 367172Sbill } 368172Sbill } 369172Sbill splx(s); 370172Sbill return (c); 371172Sbill } 372172Sbill 373172Sbill /* 374172Sbill * Put the chars in the from que 375172Sbill * on the end of the to que. 376172Sbill */ 377172Sbill catq(from, to) 37812754Ssam struct clist *from, *to; 379172Sbill { 38017542Skarels char bbuf[CBSIZE*4]; 38117542Skarels register s, c; 382172Sbill 38317542Skarels s = spltty(); 38417542Skarels if (to->c_cc == 0) { 38517542Skarels *to = *from; 38617542Skarels from->c_cc = 0; 38717542Skarels from->c_cf = NULL; 38817542Skarels from->c_cl = NULL; 38917542Skarels splx(s); 39017542Skarels return; 39117542Skarels } 39217542Skarels splx(s); 39317542Skarels while (from->c_cc > 0) { 39417542Skarels c = q_to_b(from, bbuf, sizeof bbuf); 39517542Skarels (void) b_to_q(bbuf, c, to); 39617542Skarels } 397172Sbill } 398172Sbill 39917542Skarels #ifdef unneeded 400172Sbill /* 40126279Skarels * Integer (short) get/put using clists. 40226279Skarels * Note dependency on byte order. 40332Sbill */ 40417542Skarels typedef u_short word_t; 4059761Ssam 40632Sbill getw(p) 4078955Sroot register struct clist *p; 40832Sbill { 40917542Skarels register int s, c; 41017542Skarels register struct cblock *bp; 41132Sbill 41217542Skarels if (p->c_cc <= 1) 41317542Skarels return(-1); 41417542Skarels if (p->c_cc & 01) { 41517542Skarels c = getc(p); 41626279Skarels #if defined(vax) 41726279Skarels return (c | (getc(p)<<8)); 41826279Skarels #else 41926279Skarels return (getc(p) | (c<<8)); 42026279Skarels #endif 42117542Skarels } 42217542Skarels s = spltty(); 42326279Skarels #if defined(vax) 42417542Skarels c = *((word_t *)p->c_cf); 42526279Skarels #else 42626279Skarels c = (((u_char *)p->c_cf)[1] << 8) | ((u_char *)p->c_cf)[0]; 42726279Skarels #endif 42826279Skarels p->c_cf += sizeof (word_t); 42926279Skarels p->c_cc -= sizeof (word_t); 43017542Skarels if (p->c_cc <= 0) { 43117542Skarels bp = (struct cblock *)(p->c_cf-1); 43226279Skarels bp = (struct cblock *)((int)bp & ~CROUND); 43317542Skarels p->c_cf = NULL; 43417542Skarels p->c_cl = NULL; 43517542Skarels bp->c_next = cfreelist; 43617542Skarels cfreelist = bp; 43717542Skarels cfreecount += CBSIZE; 43817542Skarels if (cwaiting) { 43917542Skarels wakeup(&cwaiting); 44017542Skarels cwaiting = 0; 44117542Skarels } 44217542Skarels } else if (((int)p->c_cf & CROUND) == 0) { 44317542Skarels bp = (struct cblock *)(p->c_cf); 44417542Skarels bp--; 44517542Skarels p->c_cf = bp->c_next->c_info; 44617542Skarels bp->c_next = cfreelist; 44717542Skarels cfreelist = bp; 44817542Skarels cfreecount += CBSIZE; 44917542Skarels if (cwaiting) { 45017542Skarels wakeup(&cwaiting); 45117542Skarels cwaiting = 0; 45217542Skarels } 45317542Skarels } 45417542Skarels splx(s); 45517542Skarels return (c); 45632Sbill } 45732Sbill 45832Sbill putw(c, p) 4598955Sroot register struct clist *p; 46017542Skarels word_t c; 46132Sbill { 46232Sbill register s; 46317542Skarels register struct cblock *bp; 46417542Skarels register char *cp; 46532Sbill 46617542Skarels s = spltty(); 46732Sbill if (cfreelist==NULL) { 46832Sbill splx(s); 46932Sbill return(-1); 47032Sbill } 47117542Skarels if (p->c_cc & 01) { 47226279Skarels #if defined(vax) 47317542Skarels (void) putc(c, p); 47417542Skarels (void) putc(c>>8, p); 47526279Skarels #else 47626279Skarels (void) putc(c>>8, p); 47726279Skarels (void) putc(c, p); 47826279Skarels #endif 47917542Skarels } else { 48017542Skarels if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { 48117542Skarels if ((bp = cfreelist) == NULL) { 48217542Skarels splx(s); 48317542Skarels return (-1); 48417542Skarels } 48517542Skarels cfreelist = bp->c_next; 48617542Skarels cfreecount -= CBSIZE; 48717542Skarels bp->c_next = NULL; 48817542Skarels p->c_cf = cp = bp->c_info; 48917542Skarels } else if (((int)cp & CROUND) == 0) { 49017542Skarels bp = (struct cblock *)cp - 1; 49117542Skarels if ((bp->c_next = cfreelist) == NULL) { 49217542Skarels splx(s); 49317542Skarels return (-1); 49417542Skarels } 49517542Skarels bp = bp->c_next; 49617542Skarels cfreelist = bp->c_next; 49717542Skarels cfreecount -= CBSIZE; 49817542Skarels bp->c_next = NULL; 49917542Skarels cp = bp->c_info; 50017542Skarels } 50126279Skarels #if defined(vax) 50217542Skarels *(word_t *)cp = c; 50326279Skarels #else 50426279Skarels ((u_char *)cp)[0] = c>>8; 50526279Skarels ((u_char *)cp)[1] = c; 50626279Skarels #endif 50726279Skarels p->c_cl = cp + sizeof (word_t); 50826279Skarels p->c_cc += sizeof (word_t); 50917542Skarels } 51032Sbill splx(s); 5119761Ssam return (0); 51232Sbill } 51317542Skarels #endif unneeded 514