static void loopbackclose(Chan *c) { Loop *lb; int ref, chan; lb = c->aux; qlock(lb); /* * closing either side hangs up the stream */ if((c->flag & COPEN) && TYPE(c->qid.path) == Qdata){ chan = ID(c->qid.path); if(--lb->link[chan].ref == 0){ qhangup(lb->link[chan ^ 1].oq, nil); looper(lb); } } /* * if both sides are closed, they are reusable */ if(lb->link[0].ref == 0 && lb->link[1].ref == 0){ for(chan = 0; chan < 2; chan++){ closelink(&lb->link[chan], 0); qreopen(lb->link[chan].iq); qreopen(lb->link[chan].oq); qsetlimit(lb->link[chan].oq, lb->link[chan].limit); qsetlimit(lb->link[chan].iq, lb->link[chan].limit); } } ref = --lb->ref; if(ref == 0) freelb(lb); qunlock(lb); }
static long loopbackwrite(Chan *c, void *va, long n, vlong off) { Loop *lb; Link *link; Cmdbuf *volatile cb; Block *volatile bp; vlong d0, d0ns; long dn, dnns; switch(TYPE(c->qid.path)){ case Qdata: bp = allocb(n); if(waserror()){ freeb(bp); nexterror(); } memmove(bp->wp, va, n); poperror(); bp->wp += n; return loopbackbwrite(c, bp, off); case Qctl: lb = c->aux; link = &lb->link[ID(c->qid.path)]; cb = parsecmd(va, n); if(waserror()){ free(cb); nexterror(); } if(cb->nf < 1) error("short control request"); if(strcmp(cb->f[0], "delay") == 0){ if(cb->nf != 3) error("usage: delay latency bytedelay"); d0ns = strtoll(cb->f[1], nil, 10); dnns = strtol(cb->f[2], nil, 10); /* * it takes about 20000 cycles on a pentium ii * to run pushlink; perhaps this should be accounted. */ ilock(link); link->delay0ns = d0ns; link->delaynns = dnns; iunlock(link); }else if(strcmp(cb->f[0], "indrop") == 0){ if(cb->nf != 2) error("usage: indrop [01]"); ilock(link); link->indrop = strtol(cb->f[1], nil, 0) != 0; iunlock(link); }else if(strcmp(cb->f[0], "droprate") == 0){ if(cb->nf != 2) error("usage: droprate ofn"); ilock(link); link->droprate = strtol(cb->f[1], nil, 0); iunlock(link); }else if(strcmp(cb->f[0], "limit") == 0){ if(cb->nf != 2) error("usage: limit maxqsize"); ilock(link); link->limit = strtol(cb->f[1], nil, 0); qsetlimit(link->oq, link->limit); qsetlimit(link->iq, link->limit); iunlock(link); }else if(strcmp(cb->f[0], "reset") == 0){ if(cb->nf != 1) error("usage: reset"); ilock(link); link->packets = 0; link->bytes = 0; link->indrop = 0; link->soverflows = 0; link->drops = 0; iunlock(link); }else error("unknown control request"); poperror(); free(cb); break; default: error(Eperm); } return n; }
int uartctl(Uart *p, char *cmd) { char *f[16]; int i, n, nf; nf = tokenize(cmd, f, nelem(f)); for(i = 0; i < nf; i++){ if(strncmp(f[i], "break", 5) == 0){ (*p->phys->dobreak)(p, 0); continue; } n = atoi(f[i]+1); switch(*f[i]){ case 'B': case 'b': uartdrainoutput(p); if((*p->phys->baud)(p, n) < 0) return -1; break; case 'C': case 'c': p->hup_dcd = n; break; case 'D': case 'd': uartdrainoutput(p); (*p->phys->dtr)(p, n); break; case 'E': case 'e': p->hup_dsr = n; break; case 'F': case 'f': if(p->oq != nil) qflush(p->oq); break; case 'H': case 'h': if(p->iq != nil) qhangup(p->iq, 0); if(p->oq != nil) qhangup(p->oq, 0); break; case 'I': case 'i': uartdrainoutput(p); (*p->phys->fifo)(p, n); break; case 'K': case 'k': uartdrainoutput(p); (*p->phys->dobreak)(p, n); break; case 'L': case 'l': uartdrainoutput(p); if((*p->phys->bits)(p, n) < 0) return -1; break; case 'M': case 'm': uartdrainoutput(p); (*p->phys->modemctl)(p, n); break; case 'N': case 'n': if(p->oq != nil) qnoblock(p->oq, n); break; case 'P': case 'p': uartdrainoutput(p); if((*p->phys->parity)(p, *(f[i]+1)) < 0) return -1; break; case 'Q': case 'q': if(p->iq != nil) qsetlimit(p->iq, n); if(p->oq != nil) qsetlimit(p->oq, n); break; case 'R': case 'r': uartdrainoutput(p); (*p->phys->rts)(p, n); break; case 'S': case 's': uartdrainoutput(p); if((*p->phys->stop)(p, n) < 0) return -1; break; case 'W': case 'w': if(uarttimer == nil || n < 1) return -1; uarttimer->tns = (int64_t)n * 100000LL; break; case 'X': case 'x': if(p->enabled){ ilock(&p->tlock); p->xonoff = n; iunlock(&p->tlock); } break; } } return 0; }
static void uartctl(Uart *p, char *cmd) { int i, n; /* let output drain for a while (up to 4 secs) */ for(i = 0; i < 200 && (qlen(p->oq) || (readstatus(p) & USTAT_TC) == 0); i++) tsleep(&up->sleep, return0, 0, 20); if(strncmp(cmd, "break", 5) == 0){ uartbreak(p, 0); return; } n = atoi(cmd+1); switch(*cmd){ case 'B': case 'b': if(n <= 0) error(Ebadarg); p->bps = n; uartset(p); break; case 'f': case 'F': qflush(p->oq); break; case 'H': case 'h': qhangup(p->iq, 0); qhangup(p->oq, 0); break; case 'L': case 'l': if(n < 7 || n > 8) error(Ebadarg); p->bits = n; uartset(p); break; case 'n': case 'N': qnoblock(p->oq, n); break; case 'P': case 'p': p->parity = *(cmd+1); uartset(p); break; case 'K': case 'k': uartbreak(p, n); break; case 'Q': case 'q': qsetlimit(p->iq, n); qsetlimit(p->oq, n); break; case 's': case 'S': if(n < 1 || n > 2) error(Ebadarg); p->stop = n; uartset(p); break; } }