1*2329Swnj /* tty_subr.c 4.5 02/01/81 */ 21892Swnj 332Sbill #include "../h/param.h" 432Sbill #include "../h/systm.h" 532Sbill #include "../h/conf.h" 632Sbill #include "../h/buf.h" 71890Swnj #include "../h/tty.h" 81950Swnj #include "tr.h" 932Sbill 1032Sbill struct cblock { 111890Swnj struct cblock *c_next; 1232Sbill char c_info[CBSIZE]; 1332Sbill }; 1432Sbill 151890Swnj struct cblock cfree[NCLIST]; 161890Swnj struct cblock *cfreelist; 1732Sbill 181890Swnj int cfreecount; 191890Swnj char cwaiting; 201890Swnj 2132Sbill /* 2232Sbill * Character list get/put 2332Sbill */ 2432Sbill getc(p) 2532Sbill register struct clist *p; 2632Sbill { 2732Sbill register struct cblock *bp; 2832Sbill register int c, s; 2932Sbill 3032Sbill s = spl6(); 3132Sbill if (p->c_cc <= 0) { 3232Sbill c = -1; 3332Sbill p->c_cc = 0; 3432Sbill p->c_cf = p->c_cl = NULL; 3532Sbill } else { 3632Sbill c = *p->c_cf++ & 0377; 3732Sbill if (--p->c_cc<=0) { 3832Sbill bp = (struct cblock *)(p->c_cf-1); 3932Sbill bp = (struct cblock *) ((int)bp & ~CROUND); 4032Sbill p->c_cf = NULL; 4132Sbill p->c_cl = NULL; 4232Sbill bp->c_next = cfreelist; 4332Sbill cfreelist = bp; 441890Swnj cfreecount += CBSIZE; 451890Swnj if (cwaiting) { 461890Swnj wakeup(&cwaiting); 471890Swnj cwaiting = 0; 481890Swnj } 4932Sbill } else if (((int)p->c_cf & CROUND) == 0){ 5032Sbill bp = (struct cblock *)(p->c_cf); 5132Sbill bp--; 5232Sbill p->c_cf = bp->c_next->c_info; 5332Sbill bp->c_next = cfreelist; 5432Sbill cfreelist = bp; 551890Swnj cfreecount += CBSIZE; 561890Swnj if (cwaiting) { 571890Swnj wakeup(&cwaiting); 581890Swnj cwaiting = 0; 591890Swnj } 6032Sbill } 6132Sbill } 6232Sbill splx(s); 6332Sbill return(c); 6432Sbill } 6532Sbill 661890Swnj #if HAVTR > 0 671890Swnj trgetc(p) 681890Swnj register struct clist *p; 691890Swnj { 701890Swnj register struct cblock *bp; 711890Swnj register int c, s; 721890Swnj 731890Swnj if (p->c_cc <= 0) { 741890Swnj c = -1; 751890Swnj p->c_cc = 0; 761890Swnj p->c_cf = NULL; 771890Swnj } else { 781890Swnj c = *p->c_cf++ & 0377; 791890Swnj if (--p->c_cc<=0) { 801890Swnj p->c_cf = NULL; 811890Swnj } else if (((int)p->c_cf & CROUND) == 0) { 821890Swnj bp = (struct cblock *)(p->c_cf); 831890Swnj bp--; 841890Swnj p->c_cf = bp->c_next->c_info; 851890Swnj } 861890Swnj } 871890Swnj return(c); 881890Swnj } 891890Swnj #endif 901890Swnj 9132Sbill /* 9232Sbill * copy clist to buffer. 9332Sbill * return number of bytes moved. 9432Sbill */ 9532Sbill q_to_b(q, cp, cc) 9632Sbill register struct clist *q; 9732Sbill register char *cp; 9832Sbill { 9932Sbill register struct cblock *bp; 10032Sbill register int s; 10132Sbill char *acp; 10232Sbill 10332Sbill if (cc <= 0) 10432Sbill return(0); 10532Sbill s = spl6(); 10632Sbill if (q->c_cc <= 0) { 10732Sbill q->c_cc = 0; 10832Sbill q->c_cf = q->c_cl = NULL; 1091890Swnj splx(s); 11032Sbill return(0); 11132Sbill } 11232Sbill acp = cp; 11332Sbill cc++; 11432Sbill 11532Sbill while (--cc) { 11632Sbill *cp++ = *q->c_cf++; 11732Sbill if (--q->c_cc <= 0) { 11832Sbill bp = (struct cblock *)(q->c_cf-1); 11932Sbill bp = (struct cblock *)((int)bp & ~CROUND); 12032Sbill q->c_cf = q->c_cl = NULL; 12132Sbill bp->c_next = cfreelist; 12232Sbill cfreelist = bp; 1231890Swnj cfreecount += CBSIZE; 1241890Swnj if (cwaiting) { 1251890Swnj wakeup(&cwaiting); 1261890Swnj cwaiting = 0; 1271890Swnj } 12832Sbill break; 12932Sbill } 13032Sbill if (((int)q->c_cf & CROUND) == 0) { 13132Sbill bp = (struct cblock *)(q->c_cf); 13232Sbill bp--; 13332Sbill q->c_cf = bp->c_next->c_info; 13432Sbill bp->c_next = cfreelist; 13532Sbill cfreelist = bp; 1361890Swnj cfreecount += CBSIZE; 1371890Swnj if (cwaiting) { 1381890Swnj wakeup(&cwaiting); 1391890Swnj cwaiting = 0; 1401890Swnj } 14132Sbill } 14232Sbill } 14332Sbill splx(s); 14432Sbill return(cp-acp); 14532Sbill } 14632Sbill 1471890Swnj #if HAVTR > 0 14832Sbill /* 1491890Swnj * Traverse a clist copying its contents to a buffer. 1501890Swnj * q->cc and q->cf are updated with the current position 1511890Swnj * in the list, but bytes are not released to the freelist. 1521890Swnj */ 1531890Swnj trq_to_b(q, cp, cc) 1541890Swnj register struct clist *q; 1551890Swnj register char *cp; 1561890Swnj register cc; 1571890Swnj { 1581890Swnj register struct cblock *bp; 1591890Swnj char *acp; 1601890Swnj 1611890Swnj if (cc <= 0) 1621890Swnj return(0); 1631890Swnj if (q->c_cc <= 0) 1641890Swnj return(0); 1651890Swnj 1661890Swnj acp = cp; 1671890Swnj cc++; 1681890Swnj while (--cc) { 1691890Swnj *cp++ = *q->c_cf++; 1701890Swnj if (((int)q->c_cf & CROUND) == 0) { 1711890Swnj bp = (struct cblock *)(q->c_cf); 1721890Swnj bp--; 1731890Swnj q->c_cf = bp->c_next->c_info; 1741890Swnj } 1751890Swnj if (--q->c_cc <= 0) 1761890Swnj break; 1771890Swnj } 1781890Swnj return(cp-acp); 1791890Swnj } 1801890Swnj #endif 1811890Swnj 1821890Swnj 1831890Swnj /* 18432Sbill * Return count of contiguous characters 18532Sbill * in clist starting at q->c_cf. 18632Sbill * Stop counting if flag&character is non-null. 18732Sbill */ 18832Sbill ndqb(q, flag) 18932Sbill register struct clist *q; 19032Sbill { 19132Sbill register cc; 19232Sbill int s; 19332Sbill 19432Sbill s = spl6(); 19532Sbill if (q->c_cc <= 0) { 19632Sbill cc = -q->c_cc; 19732Sbill goto out; 19832Sbill } 19932Sbill cc = ((int)q->c_cf + CBSIZE) & ~CROUND; 20032Sbill cc -= (int)q->c_cf; 20132Sbill if (q->c_cc < cc) 20232Sbill cc = q->c_cc; 20332Sbill if (flag) { 20432Sbill register char *p, *end; 20532Sbill 20632Sbill p = q->c_cf; 20732Sbill end = p; 20832Sbill end += cc; 20932Sbill while (p < end) { 21032Sbill if (*p & flag) { 2111890Swnj cc = (int)p; 2121890Swnj cc -= (int)q->c_cf; 21332Sbill break; 21432Sbill } 21532Sbill p++; 21632Sbill } 21732Sbill } 21832Sbill out: 21932Sbill splx(s); 22032Sbill return(cc); 22132Sbill } 22232Sbill 2231890Swnj 2241890Swnj 22532Sbill /* 2261890Swnj * Flush cc bytes from q. 22732Sbill */ 22832Sbill ndflush(q, cc) 22932Sbill register struct clist *q; 23032Sbill register cc; 23132Sbill { 2321890Swnj register struct cblock *bp; 2331890Swnj char *end; 2341890Swnj int rem; 23532Sbill register s; 23632Sbill 23732Sbill s = spl6(); 23832Sbill if (q->c_cc < 0) { 2391890Swnj printf("neg q flush\n"); 24032Sbill goto out; 24132Sbill } 24232Sbill if (q->c_cc == 0) { 24332Sbill goto out; 24432Sbill } 2451890Swnj while (cc>0 && q->c_cc) { 2461890Swnj bp = (struct cblock *)((int)q->c_cf & ~CROUND); 2471890Swnj if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) { 2481890Swnj end = q->c_cl; 2491890Swnj } else { 2501890Swnj end = (char *)((int)bp + sizeof (struct cblock)); 2511890Swnj } 2521890Swnj rem = end - q->c_cf; 2531890Swnj if (cc >= rem) { 2541890Swnj cc -= rem; 2551890Swnj q->c_cc -= rem; 25632Sbill q->c_cf = bp->c_next->c_info; 2571890Swnj bp->c_next = cfreelist; 2581890Swnj cfreelist = bp; 2591890Swnj cfreecount += CBSIZE; 2601890Swnj if (cwaiting) { 2611890Swnj wakeup(&cwaiting); 2621890Swnj cwaiting = 0; 2631890Swnj } 26432Sbill } else { 2651890Swnj q->c_cc -= cc; 2661890Swnj q->c_cf += cc; 2671890Swnj if (q->c_cc <= 0) { 2681890Swnj bp->c_next = cfreelist; 2691890Swnj cfreelist = bp; 2701890Swnj cfreecount += CBSIZE; 2711890Swnj if (cwaiting) { 2721890Swnj wakeup(&cwaiting); 2731890Swnj cwaiting = 0; 2741890Swnj } 2751890Swnj } 2761890Swnj break; 27732Sbill } 2781890Swnj } 2791890Swnj if (q->c_cc <= 0) { 28032Sbill q->c_cf = q->c_cl = NULL; 2811890Swnj q->c_cc = 0; 28232Sbill } 28332Sbill out: 28432Sbill splx(s); 28532Sbill } 286172Sbill 2871890Swnj 28832Sbill putc(c, p) 28932Sbill register struct clist *p; 29032Sbill { 29132Sbill register struct cblock *bp; 29232Sbill register char *cp; 29332Sbill register s; 29432Sbill 29532Sbill s = spl6(); 29632Sbill if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { 29732Sbill if ((bp = cfreelist) == NULL) { 29832Sbill splx(s); 29932Sbill return(-1); 30032Sbill } 30132Sbill cfreelist = bp->c_next; 3021890Swnj cfreecount -= CBSIZE; 30332Sbill bp->c_next = NULL; 30432Sbill p->c_cf = cp = bp->c_info; 30532Sbill } else if (((int)cp & CROUND) == 0) { 30632Sbill bp = (struct cblock *)cp - 1; 30732Sbill if ((bp->c_next = cfreelist) == NULL) { 30832Sbill splx(s); 30932Sbill return(-1); 31032Sbill } 31132Sbill bp = bp->c_next; 31232Sbill cfreelist = bp->c_next; 3131890Swnj cfreecount -= CBSIZE; 31432Sbill bp->c_next = NULL; 31532Sbill cp = bp->c_info; 31632Sbill } 31732Sbill *cp++ = c; 31832Sbill p->c_cc++; 31932Sbill p->c_cl = cp; 32032Sbill splx(s); 32132Sbill return(0); 32232Sbill } 32332Sbill 3241890Swnj 3251890Swnj 32632Sbill /* 32732Sbill * copy buffer to clist. 32832Sbill * return number of bytes not transfered. 32932Sbill */ 33032Sbill b_to_q(cp, cc, q) 33132Sbill register char *cp; 33232Sbill struct clist *q; 33332Sbill register int cc; 33432Sbill { 33532Sbill register char *cq; 33632Sbill register struct cblock *bp; 33732Sbill register s, acc; 33832Sbill 33932Sbill if (cc <= 0) 34032Sbill return(0); 34132Sbill acc = cc; 3421890Swnj 3431890Swnj 34432Sbill s = spl6(); 34532Sbill if ((cq = q->c_cl) == NULL || q->c_cc < 0) { 34632Sbill if ((bp = cfreelist) == NULL) 34732Sbill goto out; 34832Sbill cfreelist = bp->c_next; 3491890Swnj cfreecount -= CBSIZE; 35032Sbill bp->c_next = NULL; 35132Sbill q->c_cf = cq = bp->c_info; 35232Sbill } 35332Sbill 35432Sbill while (cc) { 35532Sbill if (((int)cq & CROUND) == 0) { 35632Sbill bp = (struct cblock *) cq - 1; 35732Sbill if ((bp->c_next = cfreelist) == NULL) 35832Sbill goto out; 35932Sbill bp = bp->c_next; 36032Sbill cfreelist = bp->c_next; 3611890Swnj cfreecount -= CBSIZE; 36232Sbill bp->c_next = NULL; 36332Sbill cq = bp->c_info; 36432Sbill } 36532Sbill *cq++ = *cp++; 36632Sbill cc--; 36732Sbill } 36832Sbill out: 36932Sbill q->c_cl = cq; 37032Sbill q->c_cc += acc-cc; 37132Sbill splx(s); 37232Sbill return(cc); 37332Sbill } 37432Sbill 3751890Swnj char * 3761890Swnj wb_to_q(cp, cc, q) 3771890Swnj register char *cp; 3781890Swnj register struct clist *q; 3791890Swnj register cc; 3801890Swnj { 3811890Swnj char *f; 3821890Swnj register s; 3831890Swnj 3841890Swnj s = spl6(); 3851890Swnj while (cc > cfreecount) { 3861890Swnj cwaiting = 1; 3871890Swnj sleep(&cwaiting, TTOPRI); 3881890Swnj } 3891890Swnj if (q->c_cc==0) { 3901890Swnj b_to_q(cp, cc, q); 3911890Swnj f = q->c_cf; 3921890Swnj } else { 3931890Swnj (void) putc(*cp++, q); 3941890Swnj f = q->c_cl; 3951890Swnj f--; 3961890Swnj b_to_q(cp, --cc, q); 3971890Swnj } 3981890Swnj splx(s); 3991890Swnj return(f); 4001890Swnj } 4011890Swnj 402*2329Swnj #ifdef UCBIPC 4031890Swnj char * 4041890Swnj nb_to_q(cp, cc, q) 4051890Swnj register char *cp; 4061890Swnj register struct clist *q; 4071890Swnj register cc; 4081890Swnj { 4091890Swnj char *f; 4101890Swnj register s; 4111890Swnj 4121890Swnj s = spl6(); 4131890Swnj if (cc > cfreecount) { 4141890Swnj f = NULL; 4151890Swnj goto out; 4161890Swnj } 4171890Swnj if (q->c_cc==0) { 4181890Swnj b_to_q(cp, cc, q); 4191890Swnj f = q->c_cf; 4201890Swnj } else { 4211890Swnj (void) putc(*cp++, q); 4221890Swnj f = q->c_cl; 4231890Swnj f--; 4241890Swnj b_to_q(cp, --cc, q); 4251890Swnj } 4261890Swnj out: 4271890Swnj splx(s); 4281890Swnj return(f); 4291890Swnj } 4301890Swnj #endif 4311890Swnj 43232Sbill /* 433172Sbill * Given a non-NULL pointter into the list (like c_cf which 434172Sbill * always points to a real character if non-NULL) return the pointer 435172Sbill * to the next character in the list or return NULL if no more chars. 436172Sbill * 437172Sbill * Callers must not allow getc's to happen between nextc's so that the 438172Sbill * pointer becomes invalid. Note that interrupts are NOT masked. 439172Sbill */ 440172Sbill char * 441172Sbill nextc(p, cp) 442172Sbill register struct clist *p; 443172Sbill register char *cp; 444172Sbill { 445172Sbill 446172Sbill if (p->c_cc && ++cp != p->c_cl) { 447172Sbill if (((int)cp & CROUND) == 0) 448172Sbill return (((struct cblock *)cp)[-1].c_next->c_info); 449172Sbill return (cp); 450172Sbill } 451172Sbill return (0); 452172Sbill } 453172Sbill 454172Sbill /* 455172Sbill * Remove the last character in the list and return it. 456172Sbill */ 457172Sbill unputc(p) 458172Sbill register struct clist *p; 459172Sbill { 460172Sbill register struct cblock *bp; 461172Sbill register int c, s; 462172Sbill struct cblock *obp; 463172Sbill 464172Sbill s = spl6(); 465172Sbill if (p->c_cc <= 0) 466172Sbill c = -1; 467172Sbill else { 468172Sbill c = *--p->c_cl; 469172Sbill if (--p->c_cc <= 0) { 470172Sbill bp = (struct cblock *)p->c_cl; 471172Sbill bp = (struct cblock *)((int)bp & ~CROUND); 472172Sbill p->c_cl = p->c_cf = NULL; 473172Sbill bp->c_next = cfreelist; 474172Sbill cfreelist = bp; 4751890Swnj cfreecount += CBSIZE; 476172Sbill } else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) { 477172Sbill p->c_cl = (char *)((int)p->c_cl & ~CROUND); 478172Sbill bp = (struct cblock *)p->c_cf; 479172Sbill bp = (struct cblock *)((int)bp & ~CROUND); 480172Sbill while (bp->c_next != (struct cblock *)p->c_cl) 481172Sbill bp = bp->c_next; 482172Sbill obp = bp; 483172Sbill p->c_cl = (char *)(bp + 1); 484172Sbill bp = bp->c_next; 485172Sbill bp->c_next = cfreelist; 486172Sbill cfreelist = bp; 4871890Swnj cfreecount += CBSIZE; 488172Sbill obp->c_next = NULL; 489172Sbill } 490172Sbill } 491172Sbill splx(s); 492172Sbill return (c); 493172Sbill } 494172Sbill 495172Sbill /* 496172Sbill * Put the chars in the from que 497172Sbill * on the end of the to que. 498172Sbill * 499172Sbill * SHOULD JUST USE q_to_b AND THEN b_to_q HERE. 500172Sbill */ 501172Sbill catq(from, to) 502172Sbill struct clist *from, *to; 503172Sbill { 504172Sbill register c; 505172Sbill 506172Sbill while ((c = getc(from)) >= 0) 507172Sbill (void) putc(c, to); 508172Sbill } 509172Sbill 510172Sbill /* 51132Sbill * Initialize clist by freeing all character blocks, then count 51232Sbill * number of character devices. (Once-only routine) 51332Sbill */ 51432Sbill cinit() 51532Sbill { 51632Sbill register int ccp; 51732Sbill register struct cblock *cp; 51832Sbill register struct cdevsw *cdp; 51932Sbill 52032Sbill ccp = (int)cfree; 52132Sbill ccp = (ccp+CROUND) & ~CROUND; 5221890Swnj for(cp=(struct cblock *)ccp; cp < &cfree[NCLIST-1]; cp++) { 52332Sbill cp->c_next = cfreelist; 52432Sbill cfreelist = cp; 5251890Swnj cfreecount += CBSIZE; 52632Sbill } 52732Sbill ccp = 0; 52832Sbill for(cdp = cdevsw; cdp->d_open; cdp++) 52932Sbill ccp++; 53032Sbill nchrdev = ccp; 53132Sbill } 53232Sbill 5331890Swnj 53432Sbill /* 53532Sbill * integer (2-byte) get/put 53632Sbill * using clists 53732Sbill */ 53832Sbill getw(p) 53932Sbill register struct clist *p; 54032Sbill { 54132Sbill register int s; 54232Sbill 54332Sbill if (p->c_cc <= 1) 54432Sbill return(-1); 54532Sbill s = getc(p); 54632Sbill return(s | (getc(p)<<8)); 54732Sbill } 54832Sbill 5491890Swnj #if HAVTR > 0 5501890Swnj trgetw(p) 5511890Swnj register struct clist *p; 5521890Swnj { 5531890Swnj register int w; 5541890Swnj 5551890Swnj if (p->c_cc <=1) 5561890Swnj return(-1); 5571890Swnj w = trgetc(p); 5581890Swnj return(w | (trgetc(p)<<8)); 5591890Swnj } 5601890Swnj #endif 5611890Swnj 56232Sbill putw(c, p) 56332Sbill register struct clist *p; 56432Sbill { 56532Sbill register s; 56632Sbill 56732Sbill s = spl6(); 56832Sbill if (cfreelist==NULL) { 56932Sbill splx(s); 57032Sbill return(-1); 57132Sbill } 572130Sbill (void) putc(c, p); 573130Sbill (void) putc(c>>8, p); 57432Sbill splx(s); 57532Sbill return(0); 57632Sbill } 577