| plan 9 kernel history: overview | file list | diff list |
1992/0520/power/devduart.c (diff list | history)
| 1992/0519/sys/src/9/power/devduart.c:6,14 – 1992/0520/sys/src/9/power/devduart.c:6,11 (short | long | prev | next) | ||
| 1991/0607 | #include "io.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1991/0607 |
| |
| 1992/0519/sys/src/9/power/devduart.c:15,23 – 1992/0520/sys/src/9/power/devduart.c:12,22 | ||
| 1991/0607 | #define PAD 15 /* registers are well-spaced */ /* | |
| 1992/0520 | * Register set for half the duart. There are really two sets in adjacent * memory locations. | |
| 1991/0607 | */ | |
| 1992/0520 | struct Duartreg { | |
| 1991/0607 | uchar mr1_2, /* Mode Register Channels 1 & 2 */ pad0[PAD]; uchar sr_csr, /* Status Register/Clock Select Register */ | |
| 1992/0519/sys/src/9/power/devduart.c:98,104 – 1992/0520/sys/src/9/power/devduart.c:97,103 | ||
| 1991/0607 | BD1200 =0x66|0x0000, BD300 =0x44|0x0000, | |
| 1992/0520 | Maxduart =8, | |
| 1991/0607 | }; /* | |
| 1992/0519/sys/src/9/power/devduart.c:115,145 – 1992/0520/sys/src/9/power/devduart.c:114,158 | ||
| 1991/0607 | }; /* | |
| 1992/0520 | * a duart | |
| 1991/0607 | */ | |
| 1992/0520 | typedef struct Duart Duart; struct Duart | |
| 1991/0607 | { QLock; | |
| 1992/0520 | Duartreg *reg; /* duart registers */ uchar imr; /* sticky interrupt mask reg bits */ uchar acr; /* sticky auxiliary reg bits */ int inited; }; Duart duart[Maxduart]; | |
| 1991/0607 | ||
| 1992/0520 | /* * values specific to a single duart port */ typedef struct Port Port; struct Port { QLock; int printing; /* true if printing */ Duart *d; /* device */ Duartreg *reg; /* duart registers (for this port) */ int c; /* character to restart output */ int op; /* operation requested */ int val; /* value of operation */ Rendez opr; /* waiot here for op to complete */ | |
| 1991/0607 | /* console interface */ | |
| 1992/0520 | int nostream; /* can't use the stream interface */ IOQ *iq; /* input character queue */ IOQ *oq; /* output character queue */ | |
| 1991/0607 | /* stream interface */ | |
| 1992/0520 | Queue *wq; /* write queue */ Rendez r; /* kproc waiting for input */ int kstarted; /* kproc started */ | |
| 1991/0607 | }; | |
| 1992/0520 | Port duartport[2*Maxduart]; | |
| 1991/0607 | /* * configure a duart port, default is 9600 baud, 8 bits/char, 1 stop bit, | |
| 1992/0519/sys/src/9/power/devduart.c:146,169 – 1992/0520/sys/src/9/power/devduart.c:159,182 | ||
| 1991/0607 | * no parity */ void | |
| 1992/0520 | duartsetup(Port *p, Duart *d, int devno) | |
| 1991/0607 | { | |
| 1992/0520 | Duartreg *reg; | |
| 1991/0607 |
| |
| 1992/0520 | p->d = d; reg = &d->reg[devno]; p->reg = reg; | |
| 1991/0607 |
| |
| 1992/0520 | reg->cmnd = RESET_RCV|DIS_TX|DIS_RX; reg->cmnd = RESET_TRANS; reg->cmnd = RESET_ERR; reg->cmnd = STOP_BRK; | |
| 1991/0607 |
| |
| 1992/0520 | reg->cmnd = RESET_MR; reg->mr1_2 = NO_PAR|CBITS8; reg->mr1_2 = ONESTOPB; reg->sr_csr = (DBD9600<<4)|DBD9600; reg->cmnd = ENB_TX|ENB_RX; | |
| 1991/0607 | } /* | |
| 1992/0519/sys/src/9/power/devduart.c:172,189 – 1992/0520/sys/src/9/power/devduart.c:185,206 | ||
| 1991/0607 | void duartinit(void) { | |
| 1992/0520 | Port *p; Duart *d; | |
| 1991/0607 |
| |
| 1992/0520 | d = &duart[m->machno]; if(d->inited) | |
| 1991/0607 | return; | |
| 1992/0520 | d->reg = DUARTREG; d->imr = IM_RRDYA|IM_XRDYA|IM_RRDYB|IM_XRDYB; d->reg->is_imr = d->imr; d->acr = 0x80; /* baud rate set 2 */ d->reg->ipc_acr = d->acr; | |
| 1991/0607 |
| |
| 1992/0520 | p = &duartport[2*m->machno]; duartsetup(p, d, 0); p++; duartsetup(p, d, 1); | |
| 1991/0607 | } /* | |
| 1992/0519/sys/src/9/power/devduart.c:190,198 – 1992/0520/sys/src/9/power/devduart.c:207,215 | ||
| 1991/0607 | * enable a duart port */ void | |
| 1992/0520 | duartenable(Port *p) | |
| 1991/0607 | { | |
| 1992/0520 | p->reg->cmnd = ENB_TX|ENB_RX; | |
| 1991/0607 | } void | |
| 1992/0519/sys/src/9/power/devduart.c:202,208 – 1992/0520/sys/src/9/power/devduart.c:219,225 | ||
| 1991/0607 | } void | |
| 1992/0520 | duartbaud(Port *p, int b) | |
| 1991/0607 | { | |
| 1992/0519 | int x; | |
| 1991/0607 | ||
| 1992/0519/sys/src/9/power/devduart.c:232,267 – 1992/0520/sys/src/9/power/devduart.c:249,284 | ||
| 1992/0516 | return; | |
| 1991/0607 | } if(x & 0x0100) | |
| 1992/0519 |
| |
| 1992/0520 | p->d->acr |= 0x80; | |
| 1991/0607 | else | |
| 1992/0519 |
| |
| 1991/0607 |
| |
| 1992/0520 | p->d->acr &= ~0x80; p->d->reg->ipc_acr = p->d->acr; p->reg->sr_csr = x; | |
| 1991/0607 | } void | |
| 1992/0520 | duartdtr(Port *p, int val) | |
| 1991/0607 | { if (val) | |
| 1992/0520 | p->reg->ctlr = 0x01; | |
| 1991/0607 | else | |
| 1992/0520 | p->reg->ctur = 0x01; | |
| 1991/0607 | } void | |
| 1992/0520 | duartbreak(Port *p, int val) | |
| 1991/0607 | { | |
| 1992/0520 | Duartreg *reg; | |
| 1991/0607 |
| |
| 1992/0520 | reg = p->reg; | |
| 1991/0607 | if (val){ | |
| 1992/0519 |
| |
| 1991/0607 |
| |
| 1992/0520 | p->d->imr &= ~IM_XRDYB; p->d->reg->is_imr = p->d->imr; reg->cmnd = STRT_BRK|ENB_TX; | |
| 1991/0607 | } else { | |
| 1992/0519 |
| |
| 1992/0520 | reg->cmnd = STOP_BRK|ENB_TX; p->d->imr |= IM_XRDYB; p->d->reg->is_imr = p->d->imr; | |
| 1991/0607 | } } | |
| 1992/0519/sys/src/9/power/devduart.c:269,335 – 1992/0520/sys/src/9/power/devduart.c:286,352 | ||
| 1991/0607 | * do anything requested for this CPU's duarts */ void | |
| 1992/0520 | duartslave0(Port *p) | |
| 1991/0607 | { | |
| 1992/0520 | switch(p->op){ | |
| 1991/0607 | case Ddtr: | |
| 1992/0519 |
| |
| 1992/0520 | duartdtr(p, p->val); | |
| 1991/0607 | break; case Dbaud: | |
| 1992/0519 |
| |
| 1992/0520 | duartbaud(p, p->val); | |
| 1991/0607 | break; case Dbreak: | |
| 1992/0520 | duartbreak(p, p->val); | |
| 1991/0607 | break; case Dprint: | |
| 1992/0520 | p->reg->cmnd = ENB_TX; p->reg->data = p->val; | |
| 1991/0607 | break; case Dena: | |
| 1992/0520 | duartenable(p); | |
| 1991/0607 | break; case Dstate: | |
| 1992/0520 | p->val = p->reg->ppcr; | |
| 1991/0607 | break; } | |
| 1992/0520 | p->op = Dnone; wakeup(&p->opr); | |
| 1991/0607 | } void duartslave(void) { | |
| 1992/0519 | IOQ *cq; | |
| 1991/0607 |
| |
| 1992/0520 | Port *p; | |
| 1991/0607 |
| |
| 1992/0519 |
| |
| 1992/0520 | p = &duartport[2*m->machno]; cq = p->iq; if(p->wq && cangetc(cq)) | |
| 1992/0519 | wakeup(&cq->r); | |
| 1991/0607 |
| |
| 1992/0519 |
| |
| 1992/0520 | if(p->op != Dnone) duartslave0(p); p++; cq = p->iq; if(p->wq && cangetc(cq)) | |
| 1992/0519 | wakeup(&cq->r); | |
| 1991/0607 |
| |
| 1992/0520 | if(p->op != Dnone) duartslave0(p); | |
| 1991/0607 | } | |
| 1992/0519 | void | |
| 1991/0607 |
| |
| 1992/0520 | duartrintr(Port *p) | |
| 1991/0607 | { | |
| 1992/0520 | Duartreg *reg; | |
| 1991/0607 | IOQ *cq; int status; char ch; | |
| 1992/0520 | reg = p->reg; status = reg->sr_csr; ch = reg->data; | |
| 1991/0607 | if(status & (FRM_ERR|OVR_ERR|PAR_ERR)) | |
| 1992/0520 | reg->cmnd = RESET_ERR; | |
| 1991/0607 |
| |
| 1992/0520 | cq = p->iq; | |
| 1991/0607 | if(cq->putc) (*cq->putc)(cq, ch); | |
| 1992/0519 | else | |
| 1992/0519/sys/src/9/power/devduart.c:337,358 – 1992/0520/sys/src/9/power/devduart.c:354,375 | ||
| 1991/0607 | } | |
| 1992/0519 | void | |
| 1991/0607 |
| |
| 1992/0520 | duartxintr(Port *p) | |
| 1991/0607 | { | |
| 1992/0520 | Duartreg *reg; | |
| 1991/0607 | IOQ *cq; | |
| 1992/0325 | int ch; | |
| 1991/0607 |
| |
| 1992/0520 | cq = p->oq; | |
| 1991/0607 | lock(cq); ch = getc(cq); | |
| 1992/0520 | reg = p->reg; | |
| 1991/0607 | if(ch < 0){ | |
| 1992/0520 | p->printing = 0; | |
| 1991/0607 | wakeup(&cq->r); | |
| 1992/0520 | reg->cmnd = DIS_TX; | |
| 1991/0607 | } else | |
| 1992/0520 | reg->data = ch; | |
| 1991/0607 | unlock(cq); } | |
| 1992/0519/sys/src/9/power/devduart.c:360,371 – 1992/0520/sys/src/9/power/devduart.c:377,389 | ||
| 1991/0607 | duartintr(void) { int cause, status, c; | |
| 1992/0520 | Duartreg *reg; Port *p; | |
| 1991/0607 |
| |
| 1992/0520 | p = &duartport[2*m->machno]; reg = p->reg; cause = reg->is_imr; | |
| 1991/0607 | /* * I can guess your interrupt. */ | |
| 1992/0519/sys/src/9/power/devduart.c:373,394 – 1992/0520/sys/src/9/power/devduart.c:391,412 | ||
| 1991/0607 | * Is it 1? */ if(cause & IM_RRDYA) | |
| 1992/0520 | duartrintr(p); | |
| 1991/0607 | /* * Is it 2? */ if(cause & IM_XRDYA) | |
| 1992/0520 | duartxintr(p); | |
| 1991/0607 | /* * Is it 3? */ if(cause & IM_RRDYB) | |
| 1992/0520 | duartrintr(p+1); | |
| 1991/0607 | /* * Is it 4? */ if(cause & IM_XRDYB) | |
| 1992/0520 | duartxintr(p+1); | |
| 1991/0607 | } /* | |
| 1992/0519/sys/src/9/power/devduart.c:397,418 – 1992/0520/sys/src/9/power/devduart.c:415,436 | ||
| 1991/0607 | int duartrawputc(int c) { | |
| 1992/0520 | Duartreg *reg; | |
| 1991/0607 | int i; | |
| 1992/0520 | reg = DUARTREG; | |
| 1991/0607 | if(c == '\n') duartrawputc('\r'); | |
| 1992/0520 | reg->cmnd = ENB_TX; | |
| 1991/0607 | i = 0; | |
| 1992/0520 | while((reg->sr_csr&XMT_RDY) == 0) | |
| 1991/0607 | if(++i >= 1000000){ | |
| 1992/0520 | duartsetup(&duartport[0], &duart[0], 0); | |
| 1991/0607 | for(i=0; i<100000; i++) ; break; } | |
| 1992/0520 | reg->data = c; | |
| 1991/0607 | if(c == '\n') for(i=0; i<100000; i++) ; | |
| 1992/0519/sys/src/9/power/devduart.c:447,465 – 1992/0520/sys/src/9/power/devduart.c:465,483 | ||
| 1991/0607 | duartputs(IOQ *cq, char *s, int n) { int ch, x; | |
| 1992/0520 | Port *p; Duartreg *reg; | |
| 1991/0607 | x = splhi(); lock(cq); puts(cq, s, n); | |
| 1992/0520 | p = cq->ptr; if(p->printing == 0){ | |
| 1991/0607 | ch = getc(cq); if(ch >= 0){ | |
| 1992/0520 | p->printing = 1; p->val = ch; p->op = Dprint; | |
| 1991/0607 | } } unlock(cq); | |
| 1992/0519/sys/src/9/power/devduart.c:472,489 – 1992/0520/sys/src/9/power/devduart.c:490,507 | ||
| 1991/0607 | void duartspecial(int port, IOQ *oq, IOQ *iq, int baud) { | |
| 1992/0520 | Port *p = &duartport[port]; | |
| 1991/0727 | IOQ *zq; | |
| 1991/0607 |
| |
| 1992/0520 | p->nostream = 1; | |
| 1991/0607 | if(oq){ | |
| 1992/0520 | p->oq = oq; p->oq->puts = duartputs; p->oq->ptr = p; | |
| 1991/0607 | } if(iq){ | |
| 1992/0520 | p->iq = iq; p->iq->ptr = p; | |
| 1991/0727 | /* * Stupid HACK to undo a stupid hack | |
| 1992/0519/sys/src/9/power/devduart.c:492,499 – 1992/0520/sys/src/9/power/devduart.c:510,517 | ||
| 1991/0727 | if(iq == zq) kbdq.putc = kbdcr2nl; | |
| 1991/0607 | } | |
| 1992/0520 | duartenable(p); duartbaud(p, baud); | |
| 1991/0607 | } static int duartputc(IOQ *, int); | |
| 1992/0519/sys/src/9/power/devduart.c:513,579 – 1992/0520/sys/src/9/power/devduart.c:531,605 | ||
| 1991/0607 | static int | |
| 1992/0519 | opdone(void *x) | |
| 1991/0607 | { | |
| 1992/0519 |
| |
| 1992/0520 | Port *p = x; | |
| 1991/0607 | ||
| 1992/0519 |
| |
| 1992/0520 | return p->op == Dnone; | |
| 1991/0607 | } static void duartstopen(Queue *q, Stream *s) { | |
| 1992/0520 | Port *p; | |
| 1991/0607 | char name[NAMELEN]; | |
| 1992/0520 | p = &duartport[s->id]; | |
| 1991/0607 |
| |
| 1992/0520 | qlock(p); p->wq = WR(q); WR(q)->ptr = p; RD(q)->ptr = p; qunlock(p); | |
| 1991/0607 |
| |
| 1992/0520 | if(p->kstarted == 0){ p->kstarted = 1; sprint(name, "duart%d", s->id+1); kproc(name, duartkproc, p); | |
| 1991/0607 | } | |
| 1992/0519 | /* enable the port */ | |
| 1992/0520 | qlock(p); p->op = Dena; sleep(&p->opr, opdone, p); qunlock(p); | |
| 1991/0607 | } static void duartstclose(Queue *q) { | |
| 1992/0520 | Port *p = q->ptr; | |
| 1991/0607 |
| |
| 1992/0520 | qlock(p); p->wq = 0; p->iq->putc = 0; | |
| 1991/0607 | WR(q)->ptr = 0; RD(q)->ptr = 0; | |
| 1992/0520 | qunlock(p); | |
| 1991/0607 | } static void duartoput(Queue *q, Block *bp) { | |
| 1992/0520 | Port *p = q->ptr; | |
| 1991/0607 | IOQ *cq; int n, m; | |
| 1992/0520 | if(p == 0){ | |
| 1991/0607 | freeb(bp); return; } | |
| 1992/0520 | cq = p->oq; | |
| 1991/0607 | if(waserror()){ freeb(bp); nexterror(); } if(bp->type == M_CTL){ | |
| 1992/0520 | if(waserror()){ qunlock(p); qunlock(p->d); nexterror(); } qlock(p); qlock(p->d); | |
| 1991/0607 | while (cangetc(cq)) /* let output drain */ sleep(&cq->r, cangetc, cq); n = strtoul((char *)(bp->rptr+1), 0, 0); | |
| 1992/0519/sys/src/9/power/devduart.c:580,604 – 1992/0520/sys/src/9/power/devduart.c:606,633 | ||
| 1991/0607 | switch(*bp->rptr){ case 'B': case 'b': | |
| 1992/0520 | p->val = n; p->op = Dbaud; sleep(&p->opr, opdone, p); | |
| 1991/0607 | break; case 'D': case 'd': | |
| 1992/0520 | p->val = n; p->op = Ddtr; sleep(&p->opr, opdone, p); | |
| 1991/0607 | break; case 'K': case 'k': | |
| 1992/0520 | p->val = 1; p->op = Dbreak; if(!waserror()){ sleep(&p->opr, opdone, p); tsleep(&p->opr, return0, 0, n); poperror(); } p->val = 0; p->op = Dbreak; sleep(&p->opr, opdone, p); | |
| 1991/0607 | break; case 'R': case 'r': | |
| 1992/0519/sys/src/9/power/devduart.c:605,611 – 1992/0520/sys/src/9/power/devduart.c:634,642 | ||
| 1991/0607 | /* can't control? */ break; } | |
| 1992/0520 | qunlock(p->d); qunlock(p); poperror(); | |
| 1991/0607 | }else while((m = BLEN(bp)) > 0){ while ((n = canputc(cq)) == 0){ kprint(" duartoput: sleeping\n"); | |
| 1992/0519/sys/src/9/power/devduart.c:626,633 – 1992/0520/sys/src/9/power/devduart.c:657,664 | ||
| 1991/0607 | static void duartkproc(void *a) { | |
| 1992/0520 | Port *p = a; IOQ *cq = p->iq; | |
| 1991/0607 | Block *bp; int n; | |
| 1992/0519/sys/src/9/power/devduart.c:634,649 – 1992/0520/sys/src/9/power/devduart.c:665,680 | ||
| 1991/0607 | loop: while ((n = cangetc(cq)) == 0) sleep(&cq->r, cangetc, cq); | |
| 1992/0520 | qlock(p); if(p->wq == 0){ | |
| 1991/0607 | cq->out = cq->in; }else{ bp = allocb(n); bp->flags |= S_DELIM; bp->wptr += gets(cq, bp->wptr, n); | |
| 1992/0520 | PUTNEXT(RD(p->wq), bp); | |
| 1991/0607 | } | |
| 1992/0520 | qunlock(p); | |
| 1991/0607 | goto loop; } | |
| 1992/0519/sys/src/9/power/devduart.c:656,662 – 1992/0520/sys/src/9/power/devduart.c:687,693 | ||
| 1991/0607 | void duartreset(void) { | |
| 1992/0520 | Port *p; | |
| 1991/0607 | int i; /* | |
| 1992/0519/sys/src/9/power/devduart.c:665,672 – 1992/0520/sys/src/9/power/devduart.c:696,703 | ||
| 1991/0607 | nduartport = 2*conf.nmach; duartdir = ialloc(nduartport*2*sizeof(Dirtab), 0); for(i = 0; i < nduartport; i++){ | |
| 1991/1115 |
| |
| 1992/0520 | sprint(duartdir[2*i].name, "eia%d", i+1); sprint(duartdir[2*i+1].name, "eia%dctl", i+1); | |
| 1992/0519 | duartdir[2*i].length = 0; duartdir[2*i+1].length = 0; duartdir[2*i].perm = 0666; | |
| 1992/0519/sys/src/9/power/devduart.c:678,695 – 1992/0520/sys/src/9/power/devduart.c:709,726 | ||
| 1991/0607 | /* * allocate queues for any stream interfaces */ | |
| 1992/0520 | for(p = duartport; p < &duartport[nduartport]; p++){ if(p->nostream) | |
| 1991/0607 | continue; | |
| 1992/0520 | p->iq = ialloc(sizeof(IOQ), 0); initq(p->iq); p->iq->ptr = p; | |
| 1991/0607 |
| |
| 1992/0520 | p->oq = ialloc(sizeof(IOQ), 0); initq(p->oq); p->oq->ptr = p; p->oq->puts = duartputs; | |
| 1991/0607 | } } | |
| 1992/0519/sys/src/9/power/devduart.c:712,725 – 1992/0520/sys/src/9/power/devduart.c:743,756 | ||
| 1991/0607 | } void | |
| 1992/0520 | duartstat(Chan *c, char *p) | |
| 1991/0607 | { switch(STREAMTYPE(c->qid.path)){ case Sdataqid: | |
| 1992/0519 |
| |
| 1992/0520 | streamstat(c, p, duartdir[2*STREAMID(c->qid.path)].name); | |
| 1991/0607 | break; default: | |
| 1992/0520 | devstat(c, p, duartdir, 2*nduartport, devgen); | |
| 1991/0607 | break; } } | |
| 1992/0519/sys/src/9/power/devduart.c:727,745 – 1992/0520/sys/src/9/power/devduart.c:758,776 | ||
| 1991/0607 | Chan* duartopen(Chan *c, int omode) { | |
| 1992/0520 | Port *p; | |
| 1991/0607 | switch(STREAMTYPE(c->qid.path)){ case Sdataqid: case Sctlqid: | |
| 1992/0520 | p = &duartport[STREAMID(c->qid.path)]; | |
| 1991/0607 | break; default: | |
| 1992/0520 | p = 0; | |
| 1991/0607 | break; } | |
| 1992/0520 | if(p && p->nostream) | |
| 1992/0114 | error(Einuse); | |
| 1991/0607 | if((c->qid.path & CHDIR) == 0) | |
| 1992/0519/sys/src/9/power/devduart.c:764,770 – 1992/0520/sys/src/9/power/devduart.c:795,801 | ||
| 1991/0607 | long duartread(Chan *c, void *buf, long n, ulong offset) { | |
| 1992/0520 | Port *p; | |
| 1991/0607 | if(c->qid.path&CHDIR) return devdirread(c, buf, n, duartdir, 2*nduartport, devgen); | |
| 1992/0519/sys/src/9/power/devduart.c:775,786 – 1992/0520/sys/src/9/power/devduart.c:806,817 | ||
| 1991/0607 | case Sctlqid: if(offset) return 0; | |
| 1992/0520 | p = &duartport[STREAMID(c->qid.path)]; qlock(p); p->op = Dstate; sleep(&p->opr, opdone, p); *(uchar *)buf = p->val; qunlock(p); | |
| 1991/0607 | return 1; } | |
| 1992/0519/sys/src/9/power/devduart.c:802,808 – 1992/0520/sys/src/9/power/devduart.c:833,839 | ||
| 1991/0607 | } void | |
| 1992/0520 | duartwstat(Chan *c, char *p) | |
| 1991/0607 | { | |
| 1991/1214 | USED(c); | |
| 1992/0114 | error(Eperm); | |