devns16552.c
来自「著名操作系统Plan 9的第三版的部分核心源代码。现在很难找到了。Plan 9是」· C语言 代码 · 共 1,209 行 · 第 1/2 页
C
1,209 行
*in = p->iq; if(out) *out = p->oq; p->opens++;}/* * handle an interrupt to a single uart */voidns16552intr(int dev){ uchar ch; int s, l, loops; Uart *p = uart[dev]; for(loops = 0;; loops++){ p->istat = s = uartrdreg(p, Istat); if(loops > 10000000){ print("lstat %ux mstat %ux istat %ux iena %ux ferr %d oerr %d", uartrdreg(p, Lstat), uartrdreg(p, Mstat), s, uartrdreg(p, Iena), p->frame, p->overrun); panic("ns16552intr"); } switch(s&0x3f){ case 6: /* receiver line status */ l = uartrdreg(p, Lstat); if(l & Ferror) p->frame++; if(l & Oerror) p->overrun++; break; case 4: /* received data available */ case 12: ch = uartrdreg(p, Data) & 0xff; if(p->xonoff){ if(ch == CTLS){ p->blocked = 1; }else if (ch == CTLQ){ p->blocked = 0; p->ctsbackoff = 2; /* clock gets output going again */ } } if(p->putc) p->putc(p->iq, ch); else { ilock(&p->rlock); if(p->ip < p->ie) *p->ip++ = ch; p->haveinput = 1; iunlock(&p->rlock); } break; case 2: /* transmitter not full */ ns16552kick(p); break; case 0: /* modem status */ ch = uartrdreg(p, Mstat); if(ch & Ctsc){ l = p->cts; p->cts = ch & Cts; if(l == 0 && p->cts) p->ctsbackoff = 2; /* clock gets output going again */ } if (ch & Dsrc) { l = ch & Dsr; if(p->hup_dsr && p->dsr && !l) p->dohup = 1; /* clock peforms hangup */ p->dsr = l; } if (ch & Dcdc) { l = ch & Dcd; if(l == 0 && p->dcd != 0 && p->dcdts && saveintrts != nil) (*saveintrts)(); if(p->hup_dcd && p->dcd && !l) p->dohup = 1; /* clock peforms hangup */ p->dcd = l; } break; default: if(s&1) return; print("weird modem interrupt #%2.2ux\n", s); break; } }}/* * we save up input characters till clock time * * There's also a bit of code to get a stalled print going. * It shouldn't happen, but it does. Obviously I don't * understand something. Since it was there, I bundled a * restart after flow control with it to give some hysteresis * to the hardware flow control. This makes compressing * modems happier but will probably bother something else. * -- presotto */voiduartclock(void){ int n; Uart *p; for(p = uartalloc.elist; p; p = p->elist){ /* this amortizes cost of qproduce to many chars */ if(p->haveinput){ ilock(&p->rlock); if(p->haveinput){ n = p->ip - p->istage; if(n > 0 && p->iq){ if(n > Stagesize) panic("uartclock"); if(qproduce(p->iq, p->istage, n) < 0) ns16552rts(p, 0); else p->ip = p->istage; } p->haveinput = 0; } iunlock(&p->rlock); } if(p->dohup){ ilock(&p->rlock); if(p->dohup){ qhangup(p->iq, 0); qhangup(p->oq, 0); } p->dohup = 0; iunlock(&p->rlock); } /* this adds hysteresis to hardware/software flow control */ if(p->ctsbackoff){ ilock(&p->tlock); if(p->ctsbackoff){ if(--(p->ctsbackoff) == 0) ns16552kick0(p); } iunlock(&p->tlock); } }}Dirtab *ns16552dir;int ndir;static voidsetlength(int i){ Uart *p; if(i > 0){ p = uart[i]; if(p && p->opens && p->iq) ns16552dir[3*i].length = qlen(p->iq); } else for(i = 0; i < nuart; i++){ p = uart[i]; if(p && p->opens && p->iq) ns16552dir[3*i].length = qlen(p->iq); }}/* * all uarts must be ns16552setup() by this point or inside of ns16552install() */static voidns16552reset(void){ int i; Dirtab *dp; ns16552install(); /* architecture specific */ ndir = 3*nuart; ns16552dir = xalloc(ndir * sizeof(Dirtab)); dp = ns16552dir; for(i = 0; i < nuart; i++){ /* 3 directory entries per port */ strcpy(dp->name, uart[i]->name); dp->qid.path = NETQID(i, Ndataqid); dp->perm = 0660; dp++; sprint(dp->name, "%sctl", uart[i]->name); dp->qid.path = NETQID(i, Nctlqid); dp->perm = 0660; dp++; sprint(dp->name, "%sstat", uart[i]->name); dp->qid.path = NETQID(i, Nstatqid); dp->perm = 0444; dp++; }}static Chan*ns16552attach(char *spec){ return devattach('t', spec);}static intns16552walk(Chan *c, char *name){ return devwalk(c, name, ns16552dir, ndir, devgen);}static voidns16552stat(Chan *c, char *dp){ if(NETTYPE(c->qid.path) == Ndataqid) setlength(NETID(c->qid.path)); devstat(c, dp, ns16552dir, ndir, devgen);}static Chan*ns16552open(Chan *c, int omode){ Uart *p; c = devopen(c, omode, ns16552dir, ndir, devgen); switch(NETTYPE(c->qid.path)){ case Nctlqid: case Ndataqid: p = uart[NETID(c->qid.path)]; if(p->kinuse) error(Ekinuse); qlock(p); if(p->opens++ == 0){ ns16552enable(p); qreopen(p->iq); qreopen(p->oq); } qunlock(p); break; } return c;}static voidns16552close(Chan *c){ Uart *p; if(c->qid.path & CHDIR) return; if((c->flag & COPEN) == 0) return; switch(NETTYPE(c->qid.path)){ case Ndataqid: case Nctlqid: p = uart[NETID(c->qid.path)]; if(p->kinuse) error(Ekinuse); qlock(p); if(--(p->opens) == 0){ ns16552disable(p); qclose(p->iq); qclose(p->oq); p->ip = p->istage; p->dcd = p->dsr = p->dohup = 0; } qunlock(p); break; }}static longuartstatus(Chan*, Uart *p, void *buf, long n, long offset){ uchar mstat, fstat, istat, tstat; char str[256]; str[0] = 0; tstat = p->sticky[Mctl]; mstat = uartrdreg(p, Mstat); istat = p->sticky[Iena]; fstat = p->sticky[Format]; snprint(str, sizeof str, "b%d c%d d%d e%d l%d m%d p%c r%d s%d\n" "%d %d %d%s%s%s%s%s\n", p->baud, p->hup_dcd, (tstat & Dtr) != 0, p->hup_dsr, (fstat & Bits8) + 5, (istat & Imstat) != 0, (fstat & Pena) ? ((fstat & Peven) ? 'e' : 'o') : 'n', (tstat & Rts) != 0, (fstat & Stop2) ? 2 : 1, p->dev, p->frame, p->overrun, p->fifoon ? " fifo" : "", (mstat & Cts) ? " cts" : "", (mstat & Dsr) ? " dsr" : "", (mstat & Dcd) ? " dcd" : "", (mstat & Ring) ? " ring" : "" ); return readstr(offset, buf, n, str);}static longns16552read(Chan *c, void *buf, long n, vlong off){ Uart *p; ulong offset = off; if(c->qid.path & CHDIR){ setlength(-1); return devdirread(c, buf, n, ns16552dir, ndir, devgen); } p = uart[NETID(c->qid.path)]; if(p->kinuse) error(Ekinuse); switch(NETTYPE(c->qid.path)){ case Ndataqid: return qread(p->iq, buf, n); case Nctlqid: return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE); case Nstatqid: return uartstatus(c, p, buf, n, offset); } return 0;}static voidns16552ctl(Uart *p, char *cmd){ int i, n; /* let output drain for a while */ for(i = 0; i < 16 && qlen(p->oq); i++) tsleep(&p->r, (int(*)(void*))qlen, p->oq, 125); if(strncmp(cmd, "break", 5) == 0){ ns16552break(p, 0); return; } n = atoi(cmd+1); switch(*cmd){ case 'B': case 'b': ns16552setbaud(p, n); break; case 'C': case 'c': ns16552dcdhup(p, n); break; case 'D': case 'd': ns16552dtr(p, n); break; case 'E': case 'e': ns16552dsrhup(p, n); 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': ns16552bits(p, n); break; case 'm': case 'M': ns16552mflow(p, n); break; case 'n': case 'N': qnoblock(p->oq, n); break; case 'P': case 'p': ns16552parity(p, *(cmd+1)); break; case 'K': case 'k': ns16552break(p, n); break; case 'R': case 'r': ns16552rts(p, n); break; case 'Q': case 'q': qsetlimit(p->iq, n); qsetlimit(p->oq, n); break; case 'T': case 't': ns16552dcdts(p, n); break; case 'W': case 'w': /* obsolete */ break; case 'X': case 'x': ilock(&p->tlock); p->xonoff = n; iunlock(&p->tlock); break; }}static longns16552write(Chan *c, void *buf, long n, vlong){ Uart *p; char cmd[32]; if(c->qid.path & CHDIR) error(Eperm); p = uart[NETID(c->qid.path)]; if(p->kinuse) error(Ekinuse); /* * The fifo's turn themselves off sometimes. * It must be something I don't understand. -- presotto */ lock(&p->flock); if((p->istat & Fenabd) == 0 && p->fifoon && p->type < Ns550) ns16552fifoon(p); unlock(&p->flock); switch(NETTYPE(c->qid.path)){ case Ndataqid: return qwrite(p->oq, buf, n); case Nctlqid: if(n >= sizeof(cmd)) n = sizeof(cmd)-1; memmove(cmd, buf, n); cmd[n] = 0; ns16552ctl(p, cmd); return n; }}static voidns16552wstat(Chan *c, char *dp){ Dir d; Dirtab *dt; if(!iseve()) error(Eperm); if(CHDIR & c->qid.path) error(Eperm); if(NETTYPE(c->qid.path) == Nstatqid) error(Eperm); dt = &ns16552dir[3 * NETID(c->qid.path)]; convM2D(dp, &d); d.mode &= 0666; dt[0].perm = dt[1].perm = d.mode;}Dev ns16552devtab = { 't', "ns16552", ns16552reset, devinit, ns16552attach, devclone, ns16552walk, ns16552stat, ns16552open, devcreate, ns16552close, ns16552read, devbread, ns16552write, devbwrite, devremove, ns16552wstat,};/* * Polling I/O routines for kernel debugging helps. */static voidns16552setuppoll(Uart *p, int rate){ ulong brconst; /* * 8 bits/character, 1 stop bit; * set rate to rate baud; * turn on Rts and Dtr. */ memmove(p->osticky, p->sticky, sizeof p->osticky); p->sticky[Format] = Bits8; uartwrreg(p, Format, 0); brconst = (UartFREQ+8*rate-1)/(16*rate); uartwrreg(p, Format, Dra); outb(p->port+Dmsb, (brconst>>8) & 0xff); outb(p->port+Dlsb, brconst & 0xff); uartwrreg(p, Format, 0); p->sticky[Mctl] = Rts|Dtr; uartwrreg(p, Mctl, 0); p->kinuse = 1;}/* * Restore serial state from before kernel took over. */static voidns16552restore(Uart *p){ ulong brconst; memmove(p->sticky, p->osticky, sizeof p->sticky); uartwrreg(p, Format, 0); brconst = (UartFREQ+8*p->baud-1)/(16*p->baud); uartwrreg(p, Format, Dra); outb(p->port+Dmsb, (brconst>>8) & 0xff); outb(p->port+Dlsb, brconst & 0xff); uartwrreg(p, Format, 0); uartwrreg(p, Mctl, 0); p->kinuse = 0;}/* BUG should be configurable */enum { WHICH = 0, RATE = 9600,};intserialgetc(void){ Uart *p; int c; if((p=uart[WHICH]) == nil) return -1; if(!p->kinuse) ns16552setuppoll(p, RATE); while((uartrdreg(p, Lstat)&Inready) == 0) ; c = inb(p->port+Data) & 0xFF; return c; // there should be a restore here but i think it will slow things down too much.}static voidserialputc(Uart *p, int c){ while((uartrdreg(p, Lstat)&Outready) == 0) ; outb(p->port+Data, c); while((uartrdreg(p, Lstat)&Outready) == 0) ;}voidserialputs(char *s, int n){ Uart *p; if((p=uart[WHICH]) == nil) return; if(!p->kinuse) ns16552setuppoll(p, RATE); while(n-- > 0){ serialputc(p, *s); if(*s == '\n') serialputc(p, '\r'); s++; } ns16552restore(p);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?