1*1892Swnj /* tty_subr.c 4.3 12/16/80 */ 2*1892Swnj 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" 832Sbill 932Sbill struct cblock { 101890Swnj struct cblock *c_next; 1132Sbill char c_info[CBSIZE]; 1232Sbill }; 1332Sbill 141890Swnj struct cblock cfree[NCLIST]; 151890Swnj struct cblock *cfreelist; 1632Sbill 171890Swnj int cfreecount; 181890Swnj char cwaiting; 191890Swnj 2032Sbill /* 2132Sbill * Character list get/put 2232Sbill */ 2332Sbill getc(p) 2432Sbill register struct clist *p; 2532Sbill { 2632Sbill register struct cblock *bp; 2732Sbill register int c, s; 2832Sbill 2932Sbill s = spl6(); 3032Sbill if (p->c_cc <= 0) { 3132Sbill c = -1; 3232Sbill p->c_cc = 0; 3332Sbill p->c_cf = p->c_cl = NULL; 3432Sbill } else { 3532Sbill c = *p->c_cf++ & 0377; 3632Sbill if (--p->c_cc<=0) { 3732Sbill bp = (struct cblock *)(p->c_cf-1); 3832Sbill bp = (struct cblock *) ((int)bp & ~CROUND); 3932Sbill p->c_cf = NULL; 4032Sbill p->c_cl = NULL; 4132Sbill bp->c_next = cfreelist; 4232Sbill cfreelist = bp; 431890Swnj cfreecount += CBSIZE; 441890Swnj if (cwaiting) { 451890Swnj wakeup(&cwaiting); 461890Swnj cwaiting = 0; 471890Swnj } 4832Sbill } else if (((int)p->c_cf & CROUND) == 0){ 4932Sbill bp = (struct cblock *)(p->c_cf); 5032Sbill bp--; 5132Sbill p->c_cf = bp->c_next->c_info; 5232Sbill bp->c_next = cfreelist; 5332Sbill cfreelist = bp; 541890Swnj cfreecount += CBSIZE; 551890Swnj if (cwaiting) { 561890Swnj wakeup(&cwaiting); 571890Swnj cwaiting = 0; 581890Swnj } 5932Sbill } 6032Sbill } 6132Sbill splx(s); 6232Sbill return(c); 6332Sbill } 6432Sbill 651890Swnj #if HAVTR > 0 661890Swnj trgetc(p) 671890Swnj register struct clist *p; 681890Swnj { 691890Swnj register struct cblock *bp; 701890Swnj register int c, s; 711890Swnj 721890Swnj if (p->c_cc <= 0) { 731890Swnj c = -1; 741890Swnj p->c_cc = 0; 751890Swnj p->c_cf = NULL; 761890Swnj } else { 771890Swnj c = *p->c_cf++ & 0377; 781890Swnj if (--p->c_cc<=0) { 791890Swnj p->c_cf = NULL; 801890Swnj } else if (((int)p->c_cf & CROUND) == 0) { 811890Swnj bp = (struct cblock *)(p->c_cf); 821890Swnj bp--; 831890Swnj p->c_cf = bp->c_next->c_info; 841890Swnj } 851890Swnj } 861890Swnj return(c); 871890Swnj } 881890Swnj #endif 891890Swnj 9032Sbill /* 9132Sbill * copy clist to buffer. 9232Sbill * return number of bytes moved. 9332Sbill */ 9432Sbill q_to_b(q, cp, cc) 9532Sbill register struct clist *q; 9632Sbill register char *cp; 9732Sbill { 9832Sbill register struct cblock *bp; 9932Sbill register int s; 10032Sbill char *acp; 10132Sbill 10232Sbill if (cc <= 0) 10332Sbill return(0); 10432Sbill s = spl6(); 10532Sbill if (q->c_cc <= 0) { 10632Sbill q->c_cc = 0; 10732Sbill q->c_cf = q->c_cl = NULL; 1081890Swnj splx(s); 10932Sbill return(0); 11032Sbill } 11132Sbill acp = cp; 11232Sbill cc++; 11332Sbill 11432Sbill while (--cc) { 11532Sbill *cp++ = *q->c_cf++; 11632Sbill if (--q->c_cc <= 0) { 11732Sbill bp = (struct cblock *)(q->c_cf-1); 11832Sbill bp = (struct cblock *)((int)bp & ~CROUND); 11932Sbill q->c_cf = q->c_cl = NULL; 12032Sbill bp->c_next = cfreelist; 12132Sbill cfreelist = bp; 1221890Swnj cfreecount += CBSIZE; 1231890Swnj if (cwaiting) { 1241890Swnj wakeup(&cwaiting); 1251890Swnj cwaiting = 0; 1261890Swnj } 12732Sbill break; 12832Sbill } 12932Sbill if (((int)q->c_cf & CROUND) == 0) { 13032Sbill bp = (struct cblock *)(q->c_cf); 13132Sbill bp--; 13232Sbill q->c_cf = bp->c_next->c_info; 13332Sbill bp->c_next = cfreelist; 13432Sbill cfreelist = bp; 1351890Swnj cfreecount += CBSIZE; 1361890Swnj if (cwaiting) { 1371890Swnj wakeup(&cwaiting); 1381890Swnj cwaiting = 0; 1391890Swnj } 14032Sbill } 14132Sbill } 14232Sbill splx(s); 14332Sbill return(cp-acp); 14432Sbill } 14532Sbill 1461890Swnj #if HAVTR > 0 14732Sbill /* 1481890Swnj * Traverse a clist copying its contents to a buffer. 1491890Swnj * q->cc and q->cf are updated with the current position 1501890Swnj * in the list, but bytes are not released to the freelist. 1511890Swnj */ 1521890Swnj trq_to_b(q, cp, cc) 1531890Swnj register struct clist *q; 1541890Swnj register char *cp; 1551890Swnj register cc; 1561890Swnj { 1571890Swnj register struct cblock *bp; 1581890Swnj char *acp; 1591890Swnj 1601890Swnj if (cc <= 0) 1611890Swnj return(0); 1621890Swnj if (q->c_cc <= 0) 1631890Swnj return(0); 1641890Swnj 1651890Swnj acp = cp; 1661890Swnj cc++; 1671890Swnj while (--cc) { 1681890Swnj *cp++ = *q->c_cf++; 1691890Swnj if (((int)q->c_cf & CROUND) == 0) { 1701890Swnj bp = (struct cblock *)(q->c_cf); 1711890Swnj bp--; 1721890Swnj q->c_cf = bp->c_next->c_info; 1731890Swnj } 1741890Swnj if (--q->c_cc <= 0) 1751890Swnj break; 1761890Swnj } 1771890Swnj return(cp-acp); 1781890Swnj } 1791890Swnj #endif 1801890Swnj 1811890Swnj 1821890Swnj /* 18332Sbill * Return count of contiguous characters 18432Sbill * in clist starting at q->c_cf. 18532Sbill * Stop counting if flag&character is non-null. 18632Sbill */ 18732Sbill ndqb(q, flag) 18832Sbill register struct clist *q; 18932Sbill { 19032Sbill register cc; 19132Sbill int s; 19232Sbill 19332Sbill s = spl6(); 19432Sbill if (q->c_cc <= 0) { 19532Sbill cc = -q->c_cc; 19632Sbill goto out; 19732Sbill } 19832Sbill cc = ((int)q->c_cf + CBSIZE) & ~CROUND; 19932Sbill cc -= (int)q->c_cf; 20032Sbill if (q->c_cc < cc) 20132Sbill cc = q->c_cc; 20232Sbill if (flag) { 20332Sbill register char *p, *end; 20432Sbill 20532Sbill p = q->c_cf; 20632Sbill end = p; 20732Sbill end += cc; 20832Sbill while (p < end) { 20932Sbill if (*p & flag) { 2101890Swnj cc = (int)p; 2111890Swnj cc -= (int)q->c_cf; 21232Sbill break; 21332Sbill } 21432Sbill p++; 21532Sbill } 21632Sbill } 21732Sbill out: 21832Sbill splx(s); 21932Sbill return(cc); 22032Sbill } 22132Sbill 2221890Swnj 2231890Swnj 22432Sbill /* 2251890Swnj * Flush cc bytes from q. 22632Sbill */ 22732Sbill ndflush(q, cc) 22832Sbill register struct clist *q; 22932Sbill register cc; 23032Sbill { 2311890Swnj register struct cblock *bp; 2321890Swnj char *end; 2331890Swnj int rem; 23432Sbill register s; 23532Sbill 23632Sbill s = spl6(); 23732Sbill if (q->c_cc < 0) { 2381890Swnj printf("neg q flush\n"); 23932Sbill goto out; 24032Sbill } 24132Sbill if (q->c_cc == 0) { 24232Sbill goto out; 24332Sbill } 2441890Swnj while (cc>0 && q->c_cc) { 2451890Swnj bp = (struct cblock *)((int)q->c_cf & ~CROUND); 2461890Swnj if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) { 2471890Swnj end = q->c_cl; 2481890Swnj } else { 2491890Swnj end = (char *)((int)bp + sizeof (struct cblock)); 2501890Swnj } 2511890Swnj rem = end - q->c_cf; 2521890Swnj if (cc >= rem) { 2531890Swnj cc -= rem; 2541890Swnj q->c_cc -= rem; 25532Sbill q->c_cf = bp->c_next->c_info; 2561890Swnj bp->c_next = cfreelist; 2571890Swnj cfreelist = bp; 2581890Swnj cfreecount += CBSIZE; 2591890Swnj if (cwaiting) { 2601890Swnj wakeup(&cwaiting); 2611890Swnj cwaiting = 0; 2621890Swnj } 26332Sbill } else { 2641890Swnj q->c_cc -= cc; 2651890Swnj q->c_cf += cc; 2661890Swnj if (q->c_cc <= 0) { 2671890Swnj bp->c_next = cfreelist; 2681890Swnj cfreelist = bp; 2691890Swnj cfreecount += CBSIZE; 2701890Swnj if (cwaiting) { 2711890Swnj wakeup(&cwaiting); 2721890Swnj cwaiting = 0; 2731890Swnj } 2741890Swnj } 2751890Swnj break; 27632Sbill } 2771890Swnj } 2781890Swnj if (q->c_cc <= 0) { 27932Sbill q->c_cf = q->c_cl = NULL; 2801890Swnj q->c_cc = 0; 28132Sbill } 28232Sbill out: 28332Sbill splx(s); 28432Sbill } 285172Sbill 2861890Swnj 28732Sbill putc(c, p) 28832Sbill register struct clist *p; 28932Sbill { 29032Sbill register struct cblock *bp; 29132Sbill register char *cp; 29232Sbill register s; 29332Sbill 29432Sbill s = spl6(); 29532Sbill if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { 29632Sbill if ((bp = cfreelist) == NULL) { 29732Sbill splx(s); 29832Sbill return(-1); 29932Sbill } 30032Sbill cfreelist = bp->c_next; 3011890Swnj cfreecount -= CBSIZE; 30232Sbill bp->c_next = NULL; 30332Sbill p->c_cf = cp = bp->c_info; 30432Sbill } else if (((int)cp & CROUND) == 0) { 30532Sbill bp = (struct cblock *)cp - 1; 30632Sbill if ((bp->c_next = cfreelist) == NULL) { 30732Sbill splx(s); 30832Sbill return(-1); 30932Sbill } 31032Sbill bp = bp->c_next; 31132Sbill cfreelist = bp->c_next; 3121890Swnj cfreecount -= CBSIZE; 31332Sbill bp->c_next = NULL; 31432Sbill cp = bp->c_info; 31532Sbill } 31632Sbill *cp++ = c; 31732Sbill p->c_cc++; 31832Sbill p->c_cl = cp; 31932Sbill splx(s); 32032Sbill return(0); 32132Sbill } 32232Sbill 3231890Swnj 3241890Swnj 32532Sbill /* 32632Sbill * copy buffer to clist. 32732Sbill * return number of bytes not transfered. 32832Sbill */ 32932Sbill b_to_q(cp, cc, q) 33032Sbill register char *cp; 33132Sbill struct clist *q; 33232Sbill register int cc; 33332Sbill { 33432Sbill register char *cq; 33532Sbill register struct cblock *bp; 33632Sbill register s, acc; 33732Sbill 33832Sbill if (cc <= 0) 33932Sbill return(0); 34032Sbill acc = cc; 3411890Swnj 3421890Swnj 34332Sbill s = spl6(); 34432Sbill if ((cq = q->c_cl) == NULL || q->c_cc < 0) { 34532Sbill if ((bp = cfreelist) == NULL) 34632Sbill goto out; 34732Sbill cfreelist = bp->c_next; 3481890Swnj cfreecount -= CBSIZE; 34932Sbill bp->c_next = NULL; 35032Sbill q->c_cf = cq = bp->c_info; 35132Sbill } 35232Sbill 35332Sbill while (cc) { 35432Sbill if (((int)cq & CROUND) == 0) { 35532Sbill bp = (struct cblock *) cq - 1; 35632Sbill if ((bp->c_next = cfreelist) == NULL) 35732Sbill goto out; 35832Sbill bp = bp->c_next; 35932Sbill cfreelist = bp->c_next; 3601890Swnj cfreecount -= CBSIZE; 36132Sbill bp->c_next = NULL; 36232Sbill cq = bp->c_info; 36332Sbill } 36432Sbill *cq++ = *cp++; 36532Sbill cc--; 36632Sbill } 36732Sbill out: 36832Sbill q->c_cl = cq; 36932Sbill q->c_cc += acc-cc; 37032Sbill splx(s); 37132Sbill return(cc); 37232Sbill } 37332Sbill 3741890Swnj char * 3751890Swnj wb_to_q(cp, cc, q) 3761890Swnj register char *cp; 3771890Swnj register struct clist *q; 3781890Swnj register cc; 3791890Swnj { 3801890Swnj char *f; 3811890Swnj register s; 3821890Swnj 3831890Swnj s = spl6(); 3841890Swnj while (cc > cfreecount) { 3851890Swnj cwaiting = 1; 3861890Swnj sleep(&cwaiting, TTOPRI); 3871890Swnj } 3881890Swnj if (q->c_cc==0) { 3891890Swnj b_to_q(cp, cc, q); 3901890Swnj f = q->c_cf; 3911890Swnj } else { 3921890Swnj (void) putc(*cp++, q); 3931890Swnj f = q->c_cl; 3941890Swnj f--; 3951890Swnj b_to_q(cp, --cc, q); 3961890Swnj } 3971890Swnj splx(s); 3981890Swnj return(f); 3991890Swnj } 4001890Swnj 4011890Swnj #ifdef notdef 4021890Swnj char * 4031890Swnj nb_to_q(cp, cc, q) 4041890Swnj register char *cp; 4051890Swnj register struct clist *q; 4061890Swnj register cc; 4071890Swnj { 4081890Swnj char *f; 4091890Swnj register s; 4101890Swnj 4111890Swnj s = spl6(); 4121890Swnj if (cc > cfreecount) { 4131890Swnj f = NULL; 4141890Swnj goto out; 4151890Swnj } 4161890Swnj if (q->c_cc==0) { 4171890Swnj b_to_q(cp, cc, q); 4181890Swnj f = q->c_cf; 4191890Swnj } else { 4201890Swnj (void) putc(*cp++, q); 4211890Swnj f = q->c_cl; 4221890Swnj f--; 4231890Swnj b_to_q(cp, --cc, q); 4241890Swnj } 4251890Swnj out: 4261890Swnj splx(s); 4271890Swnj return(f); 4281890Swnj } 4291890Swnj #endif 4301890Swnj 43132Sbill /* 432172Sbill * Given a non-NULL pointter into the list (like c_cf which 433172Sbill * always points to a real character if non-NULL) return the pointer 434172Sbill * to the next character in the list or return NULL if no more chars. 435172Sbill * 436172Sbill * Callers must not allow getc's to happen between nextc's so that the 437172Sbill * pointer becomes invalid. Note that interrupts are NOT masked. 438172Sbill */ 439172Sbill char * 440172Sbill nextc(p, cp) 441172Sbill register struct clist *p; 442172Sbill register char *cp; 443172Sbill { 444172Sbill 445172Sbill if (p->c_cc && ++cp != p->c_cl) { 446172Sbill if (((int)cp & CROUND) == 0) 447172Sbill return (((struct cblock *)cp)[-1].c_next->c_info); 448172Sbill return (cp); 449172Sbill } 450172Sbill return (0); 451172Sbill } 452172Sbill 453172Sbill /* 454172Sbill * Remove the last character in the list and return it. 455172Sbill */ 456172Sbill unputc(p) 457172Sbill register struct clist *p; 458172Sbill { 459172Sbill register struct cblock *bp; 460172Sbill register int c, s; 461172Sbill struct cblock *obp; 462172Sbill 463172Sbill s = spl6(); 464172Sbill if (p->c_cc <= 0) 465172Sbill c = -1; 466172Sbill else { 467172Sbill c = *--p->c_cl; 468172Sbill if (--p->c_cc <= 0) { 469172Sbill bp = (struct cblock *)p->c_cl; 470172Sbill bp = (struct cblock *)((int)bp & ~CROUND); 471172Sbill p->c_cl = p->c_cf = NULL; 472172Sbill bp->c_next = cfreelist; 473172Sbill cfreelist = bp; 4741890Swnj cfreecount += CBSIZE; 475172Sbill } else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) { 476172Sbill p->c_cl = (char *)((int)p->c_cl & ~CROUND); 477172Sbill bp = (struct cblock *)p->c_cf; 478172Sbill bp = (struct cblock *)((int)bp & ~CROUND); 479172Sbill while (bp->c_next != (struct cblock *)p->c_cl) 480172Sbill bp = bp->c_next; 481172Sbill obp = bp; 482172Sbill p->c_cl = (char *)(bp + 1); 483172Sbill bp = bp->c_next; 484172Sbill bp->c_next = cfreelist; 485172Sbill cfreelist = bp; 4861890Swnj cfreecount += CBSIZE; 487172Sbill obp->c_next = NULL; 488172Sbill } 489172Sbill } 490172Sbill splx(s); 491172Sbill return (c); 492172Sbill } 493172Sbill 494172Sbill /* 495172Sbill * Put the chars in the from que 496172Sbill * on the end of the to que. 497172Sbill * 498172Sbill * SHOULD JUST USE q_to_b AND THEN b_to_q HERE. 499172Sbill */ 500172Sbill catq(from, to) 501172Sbill struct clist *from, *to; 502172Sbill { 503172Sbill register c; 504172Sbill 505172Sbill while ((c = getc(from)) >= 0) 506172Sbill (void) putc(c, to); 507172Sbill } 508172Sbill 509172Sbill /* 51032Sbill * Initialize clist by freeing all character blocks, then count 51132Sbill * number of character devices. (Once-only routine) 51232Sbill */ 51332Sbill cinit() 51432Sbill { 51532Sbill register int ccp; 51632Sbill register struct cblock *cp; 51732Sbill register struct cdevsw *cdp; 51832Sbill 51932Sbill ccp = (int)cfree; 52032Sbill ccp = (ccp+CROUND) & ~CROUND; 5211890Swnj for(cp=(struct cblock *)ccp; cp < &cfree[NCLIST-1]; cp++) { 52232Sbill cp->c_next = cfreelist; 52332Sbill cfreelist = cp; 5241890Swnj cfreecount += CBSIZE; 52532Sbill } 52632Sbill ccp = 0; 52732Sbill for(cdp = cdevsw; cdp->d_open; cdp++) 52832Sbill ccp++; 52932Sbill nchrdev = ccp; 53032Sbill } 53132Sbill 5321890Swnj 53332Sbill /* 53432Sbill * integer (2-byte) get/put 53532Sbill * using clists 53632Sbill */ 53732Sbill getw(p) 53832Sbill register struct clist *p; 53932Sbill { 54032Sbill register int s; 54132Sbill 54232Sbill if (p->c_cc <= 1) 54332Sbill return(-1); 54432Sbill s = getc(p); 54532Sbill return(s | (getc(p)<<8)); 54632Sbill } 54732Sbill 5481890Swnj #if HAVTR > 0 5491890Swnj trgetw(p) 5501890Swnj register struct clist *p; 5511890Swnj { 5521890Swnj register int w; 5531890Swnj 5541890Swnj if (p->c_cc <=1) 5551890Swnj return(-1); 5561890Swnj w = trgetc(p); 5571890Swnj return(w | (trgetc(p)<<8)); 5581890Swnj } 5591890Swnj #endif 5601890Swnj 56132Sbill putw(c, p) 56232Sbill register struct clist *p; 56332Sbill { 56432Sbill register s; 56532Sbill 56632Sbill s = spl6(); 56732Sbill if (cfreelist==NULL) { 56832Sbill splx(s); 56932Sbill return(-1); 57032Sbill } 571130Sbill (void) putc(c, p); 572130Sbill (void) putc(c>>8, p); 57332Sbill splx(s); 57432Sbill return(0); 57532Sbill } 576