149589Sbostic /*- 263178Sbostic * Copyright (c) 1982, 1986, 1993 363178Sbostic * The Regents of the University of California. All rights reserved. 423391Smckusick * 549589Sbostic * %sccs.include.proprietary.c% 649589Sbostic * 7*64411Sbostic * @(#)tty_subr.c 8.2 (Berkeley) 09/05/93 823391Smckusick */ 91892Swnj 1056517Sbostic #include <sys/param.h> 1156517Sbostic #include <sys/systm.h> 1256517Sbostic #include <sys/buf.h> 1356517Sbostic #include <sys/ioctl.h> 1456517Sbostic #include <sys/proc.h> 1556517Sbostic #include <sys/tty.h> 1656517Sbostic #include <sys/clist.h> 1732Sbill 181890Swnj char cwaiting; 1961303Ssklower struct cblock *cfree, *cfreelist; 2061303Ssklower int cfreecount, nclist; 211890Swnj 2235811Smarc #define setquote(cp) \ 2335811Smarc setbit(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \ 2435811Smarc (int)(cp)&CROUND) 2535811Smarc #define isquote(cp) \ 2635811Smarc isset(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \ 2735811Smarc (int)(cp)&CROUND) 2835811Smarc #define cbptr(x) ((struct cblock *)(x)) 2935811Smarc 3032Sbill /* 3147545Skarels * Initialize clist by freeing all character blocks. 3247545Skarels */ 33*64411Sbostic void 34*64411Sbostic clist_init() 3547545Skarels { 3647545Skarels register int ccp; 3747545Skarels register struct cblock *cp; 3847545Skarels 3947545Skarels ccp = (int) cfree; 4047545Skarels ccp = (ccp + CROUND) & ~CROUND; 4147545Skarels for(cp = (struct cblock *) ccp; cp < &cfree[nclist - 1]; cp++) { 4247545Skarels cp->c_next = cfreelist; 4347545Skarels cfreelist = cp; 4447545Skarels cfreecount += CBSIZE; 4547545Skarels } 4647545Skarels } 4747545Skarels 4847545Skarels /* 4932Sbill * Character list get/put 5032Sbill */ 5132Sbill getc(p) 5212754Ssam register struct clist *p; 5332Sbill { 5432Sbill register struct cblock *bp; 5532Sbill register int c, s; 5632Sbill 5717542Skarels s = spltty(); 5832Sbill if (p->c_cc <= 0) { 5932Sbill c = -1; 6032Sbill p->c_cc = 0; 6132Sbill p->c_cf = p->c_cl = NULL; 6232Sbill } else { 6335811Smarc c = *p->c_cf & 0377; 6435811Smarc if (isquote(p->c_cf)) 6535811Smarc c |= TTY_QUOTE; 6635811Smarc p->c_cf++; 6732Sbill if (--p->c_cc<=0) { 6835811Smarc bp = cbptr(p->c_cf-1); 6935811Smarc bp = cbptr((int)bp & ~CROUND); 7032Sbill p->c_cf = NULL; 7132Sbill p->c_cl = NULL; 7232Sbill bp->c_next = cfreelist; 7332Sbill cfreelist = bp; 741890Swnj cfreecount += CBSIZE; 751890Swnj if (cwaiting) { 761890Swnj wakeup(&cwaiting); 771890Swnj cwaiting = 0; 781890Swnj } 7932Sbill } else if (((int)p->c_cf & CROUND) == 0){ 8035811Smarc bp = cbptr(p->c_cf); 8132Sbill bp--; 8232Sbill p->c_cf = bp->c_next->c_info; 8332Sbill bp->c_next = cfreelist; 8432Sbill cfreelist = bp; 851890Swnj cfreecount += CBSIZE; 861890Swnj if (cwaiting) { 871890Swnj wakeup(&cwaiting); 881890Swnj cwaiting = 0; 891890Swnj } 9032Sbill } 9132Sbill } 9232Sbill splx(s); 9326279Skarels return (c); 9432Sbill } 9532Sbill 9632Sbill /* 9732Sbill * copy clist to buffer. 9832Sbill * return number of bytes moved. 9932Sbill */ 10032Sbill q_to_b(q, cp, cc) 1019761Ssam register struct clist *q; 1029761Ssam register char *cp; 10352501Storek int cc; 10432Sbill { 10532Sbill register struct cblock *bp; 10652501Storek register int s, nc; 10732Sbill char *acp; 10832Sbill 10932Sbill if (cc <= 0) 11026279Skarels return (0); 11117542Skarels s = spltty(); 11232Sbill if (q->c_cc <= 0) { 11332Sbill q->c_cc = 0; 11432Sbill q->c_cf = q->c_cl = NULL; 1151890Swnj splx(s); 11626279Skarels return (0); 11732Sbill } 11832Sbill acp = cp; 11932Sbill 12017542Skarels while (cc) { 12126279Skarels nc = sizeof (struct cblock) - ((int)q->c_cf & CROUND); 12255058Spendry nc = min(nc, cc); 12355058Spendry nc = min(nc, q->c_cc); 12417542Skarels (void) bcopy(q->c_cf, cp, (unsigned)nc); 12517542Skarels q->c_cf += nc; 12617542Skarels q->c_cc -= nc; 12717542Skarels cc -= nc; 12817542Skarels cp += nc; 12917542Skarels if (q->c_cc <= 0) { 13035811Smarc bp = cbptr(q->c_cf - 1); 13135811Smarc bp = cbptr((int)bp & ~CROUND); 13232Sbill q->c_cf = q->c_cl = NULL; 13332Sbill bp->c_next = cfreelist; 13432Sbill cfreelist = bp; 1351890Swnj cfreecount += CBSIZE; 1361890Swnj if (cwaiting) { 1371890Swnj wakeup(&cwaiting); 1381890Swnj cwaiting = 0; 1391890Swnj } 14032Sbill break; 14132Sbill } 14232Sbill if (((int)q->c_cf & CROUND) == 0) { 14335811Smarc bp = cbptr(q->c_cf); 14432Sbill bp--; 14532Sbill q->c_cf = bp->c_next->c_info; 14632Sbill bp->c_next = cfreelist; 14732Sbill cfreelist = bp; 1481890Swnj cfreecount += CBSIZE; 1491890Swnj if (cwaiting) { 1501890Swnj wakeup(&cwaiting); 1511890Swnj cwaiting = 0; 1521890Swnj } 15332Sbill } 15432Sbill } 15532Sbill splx(s); 15626279Skarels return (cp-acp); 15732Sbill } 15832Sbill 15932Sbill /* 16032Sbill * Return count of contiguous characters 16132Sbill * in clist starting at q->c_cf. 16232Sbill * Stop counting if flag&character is non-null. 16332Sbill */ 16432Sbill ndqb(q, flag) 1659761Ssam register struct clist *q; 16652501Storek int flag; 16732Sbill { 16852501Storek register int cc, s; 16932Sbill 17017542Skarels s = spltty(); 17132Sbill if (q->c_cc <= 0) { 17232Sbill cc = -q->c_cc; 17332Sbill goto out; 17432Sbill } 17532Sbill cc = ((int)q->c_cf + CBSIZE) & ~CROUND; 17632Sbill cc -= (int)q->c_cf; 17732Sbill if (q->c_cc < cc) 17832Sbill cc = q->c_cc; 17932Sbill if (flag) { 18032Sbill register char *p, *end; 18132Sbill 18232Sbill p = q->c_cf; 18332Sbill end = p; 18432Sbill end += cc; 18532Sbill while (p < end) { 18632Sbill if (*p & flag) { 1871890Swnj cc = (int)p; 1881890Swnj cc -= (int)q->c_cf; 18932Sbill break; 19032Sbill } 19132Sbill p++; 19232Sbill } 19332Sbill } 19432Sbill out: 19532Sbill splx(s); 19626279Skarels return (cc); 19732Sbill } 19832Sbill 19932Sbill /* 2001890Swnj * Flush cc bytes from q. 20132Sbill */ 202*64411Sbostic void 20332Sbill ndflush(q, cc) 20412754Ssam register struct clist *q; 20552501Storek register int cc; 20632Sbill { 20712754Ssam register struct cblock *bp; 20812754Ssam char *end; 20912754Ssam int rem, s; 21032Sbill 21117542Skarels s = spltty(); 21226279Skarels if (q->c_cc <= 0) 21332Sbill goto out; 2141890Swnj while (cc>0 && q->c_cc) { 21535811Smarc bp = cbptr((int)q->c_cf & ~CROUND); 2161890Swnj if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) { 2171890Swnj end = q->c_cl; 2181890Swnj } else { 2191890Swnj end = (char *)((int)bp + sizeof (struct cblock)); 2201890Swnj } 2211890Swnj rem = end - q->c_cf; 2221890Swnj if (cc >= rem) { 2231890Swnj cc -= rem; 2241890Swnj q->c_cc -= rem; 22532Sbill q->c_cf = bp->c_next->c_info; 2261890Swnj bp->c_next = cfreelist; 2271890Swnj cfreelist = bp; 2281890Swnj cfreecount += CBSIZE; 2291890Swnj if (cwaiting) { 2301890Swnj wakeup(&cwaiting); 2311890Swnj cwaiting = 0; 2321890Swnj } 23332Sbill } else { 2341890Swnj q->c_cc -= cc; 2351890Swnj q->c_cf += cc; 2361890Swnj if (q->c_cc <= 0) { 2371890Swnj bp->c_next = cfreelist; 2381890Swnj cfreelist = bp; 2391890Swnj cfreecount += CBSIZE; 2401890Swnj if (cwaiting) { 2411890Swnj wakeup(&cwaiting); 2421890Swnj cwaiting = 0; 2431890Swnj } 2441890Swnj } 2451890Swnj break; 24632Sbill } 2471890Swnj } 2481890Swnj if (q->c_cc <= 0) { 24932Sbill q->c_cf = q->c_cl = NULL; 2501890Swnj q->c_cc = 0; 25132Sbill } 25232Sbill out: 25332Sbill splx(s); 25432Sbill } 255172Sbill 2561890Swnj 25732Sbill putc(c, p) 25852501Storek int c; 25912754Ssam register struct clist *p; 26032Sbill { 26132Sbill register struct cblock *bp; 26232Sbill register char *cp; 26352501Storek register int s; 26432Sbill 26517542Skarels s = spltty(); 26635811Smarc if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { /* no cblocks yet */ 26732Sbill if ((bp = cfreelist) == NULL) { 26832Sbill splx(s); 26926279Skarels return (-1); 27032Sbill } 27132Sbill cfreelist = bp->c_next; 2721890Swnj cfreecount -= CBSIZE; 27332Sbill bp->c_next = NULL; 27435811Smarc bzero(bp->c_quote, CBQSIZE); 27532Sbill p->c_cf = cp = bp->c_info; 27632Sbill } else if (((int)cp & CROUND) == 0) { 27735811Smarc bp = cbptr(cp) - 1; /* pointer arith */ 27832Sbill if ((bp->c_next = cfreelist) == NULL) { 27932Sbill splx(s); 28026279Skarels return (-1); 28132Sbill } 28232Sbill bp = bp->c_next; 28332Sbill cfreelist = bp->c_next; 2841890Swnj cfreecount -= CBSIZE; 28532Sbill bp->c_next = NULL; 28632Sbill cp = bp->c_info; 28732Sbill } 28835811Smarc if (c&TTY_QUOTE) 28935811Smarc setquote(cp); 29032Sbill *cp++ = c; 29132Sbill p->c_cc++; 29232Sbill p->c_cl = cp; 29332Sbill splx(s); 29426279Skarels return (0); 29532Sbill } 29632Sbill 29732Sbill /* 29832Sbill * copy buffer to clist. 29932Sbill * return number of bytes not transfered. 30032Sbill */ 30132Sbill b_to_q(cp, cc, q) 30212754Ssam register char *cp; 30312754Ssam struct clist *q; 30412754Ssam register int cc; 30532Sbill { 30632Sbill register char *cq; 30732Sbill register struct cblock *bp; 30852501Storek register int s, nc; 30917542Skarels int acc; 31032Sbill 31132Sbill if (cc <= 0) 31226279Skarels return (0); 31317542Skarels acc = cc; 31417542Skarels s = spltty(); 31517542Skarels if ((cq = q->c_cl) == NULL || q->c_cc < 0) { 31617542Skarels if ((bp = cfreelist) == NULL) 31717542Skarels goto out; 31817542Skarels cfreelist = bp->c_next; 31917542Skarels cfreecount -= CBSIZE; 32035811Smarc bzero(bp->c_quote, CBQSIZE); 32117542Skarels bp->c_next = NULL; 32217542Skarels q->c_cf = cq = bp->c_info; 32317542Skarels } 32417542Skarels 32517542Skarels while (cc) { 32632Sbill if (((int)cq & CROUND) == 0) { 32735811Smarc bp = cbptr(cq) - 1; 32817542Skarels if ((bp->c_next = cfreelist) == NULL) 32917542Skarels goto out; 33032Sbill bp = bp->c_next; 33132Sbill cfreelist = bp->c_next; 3321890Swnj cfreecount -= CBSIZE; 33335811Smarc bzero(bp->c_quote, CBQSIZE); 33432Sbill bp->c_next = NULL; 33517542Skarels cq = bp->c_info; 33632Sbill } 33755058Spendry nc = min(cc, sizeof (struct cblock) - ((int)cq & CROUND)); 33817542Skarels (void) bcopy(cp, cq, (unsigned)nc); 33917542Skarels cp += nc; 34017542Skarels cq += nc; 34117542Skarels cc -= nc; 34232Sbill } 34317542Skarels out: 34417542Skarels q->c_cl = cq; 34517542Skarels q->c_cc += acc - cc; 34617542Skarels splx(s); 34717368Ssam return (cc); 34832Sbill } 34932Sbill 35032Sbill /* 351172Sbill * Given a non-NULL pointter into the list (like c_cf which 352172Sbill * always points to a real character if non-NULL) return the pointer 353172Sbill * to the next character in the list or return NULL if no more chars. 354172Sbill * 355172Sbill * Callers must not allow getc's to happen between nextc's so that the 356172Sbill * pointer becomes invalid. Note that interrupts are NOT masked. 357172Sbill */ 358172Sbill char * 35935811Smarc nextc(p, cp, c) 36012754Ssam register struct clist *p; 36112754Ssam register char *cp; 36235811Smarc register int *c; 363172Sbill { 364172Sbill 365172Sbill if (p->c_cc && ++cp != p->c_cl) { 36635811Smarc if (((int)cp & CROUND) == 0) { 36735811Smarc cp = (cbptr(cp))[-1].c_next->c_info; 36835811Smarc } 36935811Smarc *c = *cp; 37035811Smarc if (isquote(cp)) 37135811Smarc *c |= TTY_QUOTE; 372172Sbill return (cp); 373172Sbill } 374172Sbill return (0); 375172Sbill } 376172Sbill 377172Sbill /* 378172Sbill * Remove the last character in the list and return it. 379172Sbill */ 380172Sbill unputc(p) 38112754Ssam register struct clist *p; 382172Sbill { 383172Sbill register struct cblock *bp; 384172Sbill register int c, s; 385172Sbill struct cblock *obp; 386172Sbill 38717542Skarels s = spltty(); 388172Sbill if (p->c_cc <= 0) 389172Sbill c = -1; 390172Sbill else { 391172Sbill c = *--p->c_cl; 39235811Smarc if (isquote(p->c_cl)) 39335811Smarc c |= TTY_QUOTE; 394172Sbill if (--p->c_cc <= 0) { 39535811Smarc bp = cbptr(p->c_cl); 39635811Smarc bp = cbptr((int)bp & ~CROUND); 397172Sbill p->c_cl = p->c_cf = NULL; 398172Sbill bp->c_next = cfreelist; 399172Sbill cfreelist = bp; 4001890Swnj cfreecount += CBSIZE; 40135811Smarc } else if (p->c_cl == (cbptr((int)p->c_cl & ~CROUND))->c_info) { 402172Sbill p->c_cl = (char *)((int)p->c_cl & ~CROUND); 40335811Smarc 40435811Smarc bp = cbptr(p->c_cf); 40535811Smarc bp = cbptr((int)bp & ~CROUND); 40635811Smarc while (bp->c_next != cbptr(p->c_cl)) 407172Sbill bp = bp->c_next; 408172Sbill obp = bp; 409172Sbill p->c_cl = (char *)(bp + 1); 410172Sbill bp = bp->c_next; 411172Sbill bp->c_next = cfreelist; 412172Sbill cfreelist = bp; 4131890Swnj cfreecount += CBSIZE; 414172Sbill obp->c_next = NULL; 415172Sbill } 416172Sbill } 417172Sbill splx(s); 418172Sbill return (c); 419172Sbill } 420172Sbill 421172Sbill /* 422172Sbill * Put the chars in the from que 423172Sbill * on the end of the to que. 424172Sbill */ 425*64411Sbostic void 426172Sbill catq(from, to) 42712754Ssam struct clist *from, *to; 428172Sbill { 42935811Smarc #ifdef notdef 43017542Skarels char bbuf[CBSIZE*4]; 43135811Smarc #endif 43252501Storek register int s, c; 433172Sbill 43417542Skarels s = spltty(); 43517542Skarels if (to->c_cc == 0) { 43617542Skarels *to = *from; 43717542Skarels from->c_cc = 0; 43817542Skarels from->c_cf = NULL; 43917542Skarels from->c_cl = NULL; 44017542Skarels splx(s); 44117542Skarels return; 44217542Skarels } 44317542Skarels splx(s); 44435811Smarc #ifdef notdef 44517542Skarels while (from->c_cc > 0) { 44617542Skarels c = q_to_b(from, bbuf, sizeof bbuf); 44717542Skarels (void) b_to_q(bbuf, c, to); 44817542Skarels } 44935811Smarc #endif 45035811Smarc /* XXX - FIX */ 45135811Smarc while ((c = getc(from)) >= 0) 45235811Smarc putc(c, to); 453172Sbill } 454172Sbill 45517542Skarels #ifdef unneeded 456172Sbill /* 45726279Skarels * Integer (short) get/put using clists. 45832Sbill */ 45917542Skarels typedef u_short word_t; 4609761Ssam 46132Sbill getw(p) 4628955Sroot register struct clist *p; 46332Sbill { 46417542Skarels register int s, c; 46517542Skarels register struct cblock *bp; 46632Sbill 46717542Skarels if (p->c_cc <= 1) 46817542Skarels return(-1); 46917542Skarels if (p->c_cc & 01) { 47017542Skarels c = getc(p); 47133398Smckusick #if BYTE_ORDER == LITTLE_ENDIAN 47226279Skarels return (c | (getc(p)<<8)); 47326279Skarels #else 47426279Skarels return (getc(p) | (c<<8)); 47526279Skarels #endif 47617542Skarels } 47717542Skarels s = spltty(); 47835811Smarc #if BYTE_ORDER == LITTLE_ENDIAN 47929947Skarels c = (((u_char *)p->c_cf)[0] << 8) | ((u_char *)p->c_cf)[1]; 48026279Skarels #else 48126279Skarels c = (((u_char *)p->c_cf)[1] << 8) | ((u_char *)p->c_cf)[0]; 48226279Skarels #endif 48326279Skarels p->c_cf += sizeof (word_t); 48426279Skarels p->c_cc -= sizeof (word_t); 48517542Skarels if (p->c_cc <= 0) { 48635811Smarc bp = cbptr(p->c_cf-1); 48735811Smarc bp = cbptr((int)bp & ~CROUND); 48817542Skarels p->c_cf = NULL; 48917542Skarels p->c_cl = NULL; 49017542Skarels bp->c_next = cfreelist; 49117542Skarels cfreelist = bp; 49217542Skarels cfreecount += CBSIZE; 49317542Skarels if (cwaiting) { 49417542Skarels wakeup(&cwaiting); 49517542Skarels cwaiting = 0; 49617542Skarels } 49717542Skarels } else if (((int)p->c_cf & CROUND) == 0) { 49835811Smarc bp = cbptr(p->c_cf); 49917542Skarels bp--; 50017542Skarels p->c_cf = bp->c_next->c_info; 50117542Skarels bp->c_next = cfreelist; 50217542Skarels cfreelist = bp; 50317542Skarels cfreecount += CBSIZE; 50417542Skarels if (cwaiting) { 50517542Skarels wakeup(&cwaiting); 50617542Skarels cwaiting = 0; 50717542Skarels } 50817542Skarels } 50917542Skarels splx(s); 51017542Skarels return (c); 51132Sbill } 51232Sbill 51332Sbill putw(c, p) 5148955Sroot register struct clist *p; 51517542Skarels word_t c; 51632Sbill { 51752501Storek register int s; 51817542Skarels register struct cblock *bp; 51917542Skarels register char *cp; 52032Sbill 52117542Skarels s = spltty(); 52232Sbill if (cfreelist==NULL) { 52332Sbill splx(s); 52432Sbill return(-1); 52532Sbill } 52617542Skarels if (p->c_cc & 01) { 52733398Smckusick #if BYTE_ORDER == LITTLE_ENDIAN 52817542Skarels (void) putc(c, p); 52917542Skarels (void) putc(c>>8, p); 53026279Skarels #else 53126279Skarels (void) putc(c>>8, p); 53226279Skarels (void) putc(c, p); 53326279Skarels #endif 53417542Skarels } else { 53517542Skarels if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { 53617542Skarels if ((bp = cfreelist) == NULL) { 53717542Skarels splx(s); 53817542Skarels return (-1); 53917542Skarels } 54017542Skarels cfreelist = bp->c_next; 54117542Skarels cfreecount -= CBSIZE; 54217542Skarels bp->c_next = NULL; 54317542Skarels p->c_cf = cp = bp->c_info; 54417542Skarels } else if (((int)cp & CROUND) == 0) { 54535811Smarc bp = cbptr(cp) - 1; 54617542Skarels if ((bp->c_next = cfreelist) == NULL) { 54717542Skarels splx(s); 54817542Skarels return (-1); 54917542Skarels } 55017542Skarels bp = bp->c_next; 55117542Skarels cfreelist = bp->c_next; 55217542Skarels cfreecount -= CBSIZE; 55317542Skarels bp->c_next = NULL; 55417542Skarels cp = bp->c_info; 55517542Skarels } 55626279Skarels #if defined(vax) 55717542Skarels *(word_t *)cp = c; 55826279Skarels #else 55926279Skarels ((u_char *)cp)[0] = c>>8; 56026279Skarels ((u_char *)cp)[1] = c; 56126279Skarels #endif 56226279Skarels p->c_cl = cp + sizeof (word_t); 56326279Skarels p->c_cc += sizeof (word_t); 56417542Skarels } 56532Sbill splx(s); 5669761Ssam return (0); 56732Sbill } 56860348Storek #endif /* unneeded */ 569