| plan 9 kernel history: overview | file list | diff list |
1992/1222/pc/devether.c (diff list | history)
| 1992/1015/sys/src/9/pc/devether.c:7,12 – 1992/1222/sys/src/9/pc/devether.c:7,14 (short | long | prev | next) | ||
| 1992/0403 | #include "io.h" #include "devtab.h" | |
| 1992/1222 | #include "ether.h" | |
| 1992/0922 | /* * Half-arsed attempt at a general top-level * ethernet driver. Needs work: | |
| 1992/1015/sys/src/9/pc/devether.c:14,48 – 1992/1222/sys/src/9/pc/devether.c:16,50 | ||
| 1992/0922 | * much tidying * set ethernet address */ | |
| 1992/1222 | extern Board ether8003; extern Board ether503; extern Board ether2000; extern Board ether509; | |
| 1992/0403 | ||
| 1992/0922 |
| |
| 1992/1222 | /* * The ordering here is important for those boards * using the DP8390 (WD8003, 3COM503 and NE2000) as * attempting to determine if a board is a NE2000 * cannot be done passively, so it must be last to * prevent scrogging one of the others. */ static Board *boards[] = { ðer8003, ðer503, ðer2000, | |
| 1992/0922 | ðer509, | |
| 1992/0404 | }; enum { | |
| 1992/0922 |
| |
| 1992/1222 | NCtlr = 1, | |
| 1992/0424 | }; | |
| 1992/0403 | ||
| 1992/0922 |
| |
| 1992/1222 | static struct Ctlr *softctlr[NCtlr]; static int nctlr; | |
| 1992/0922 | ||
| 1992/0424 |
| |
| 1992/0403 | ||
| 1992/0425 | Chan* | |
| 1992/0424 |
| |
| 1992/0917 |
| |
| 1992/0425 |
| |
| 1992/0424 |
| |
| 1992/0411 | ||
| 1992/0424 |
| |
| 1992/0411 | { | |
| 1992/0424 | return devclone(c, nc); | |
| 1992/1015/sys/src/9/pc/devether.c:51,69 – 1992/1222/sys/src/9/pc/devether.c:53,71 | ||
| 1992/0424 | int etherwalk(Chan *c, char *name) { | |
| 1992/1222 | return netwalk(c, name, &softctlr[0]->net); | |
| 1992/0424 | } void etherstat(Chan *c, char *dp) { | |
| 1992/1222 | netstat(c, dp, &softctlr[0]->net); | |
| 1992/0424 | } Chan* etheropen(Chan *c, int omode) { | |
| 1992/1222 | return netopen(c, omode, &softctlr[0]->net); | |
| 1992/0424 | } void | |
| 1992/1015/sys/src/9/pc/devether.c:83,89 – 1992/1222/sys/src/9/pc/devether.c:85,91 | ||
| 1992/0424 | long etherread(Chan *c, void *a, long n, ulong offset) { | |
| 1992/1222 | return netread(c, a, n, offset, &softctlr[0]->net); | |
| 1992/0411 | } | |
| 1992/0424 | long | |
| 1992/1015/sys/src/9/pc/devether.c:103,268 – 1992/1222/sys/src/9/pc/devether.c:105,297 | ||
| 1992/0424 | void etherwstat(Chan *c, char *dp) { | |
| 1992/1222 | netwstat(c, dp, &softctlr[0]->net); | |
| 1992/0424 | } | |
| 1992/0407 | static int | |
| 1992/0424 | isobuf(void *arg) | |
| 1992/0407 | { | |
| 1992/0922 |
| |
| 1992/1222 | Ctlr *ctlr = arg; | |
| 1992/0407 | ||
| 1992/0425 |
| |
| 1992/1222 | return ctlr->tb[ctlr->th].owner == Host; | |
| 1992/0407 | } | |
| 1992/0403 | static void etheroput(Queue *q, Block *bp) { | |
| 1992/0922 |
| |
| 1992/0403 |
| |
| 1992/0922 |
| |
| 1992/1222 | Ctlr *ctlr; Type *type; Etherpkt *pkt; RingBuf *ring; | |
| 1992/0922 | int len, n; | |
| 1992/0403 | Block *nbp; | |
| 1992/1222 | type = q->ptr; ctlr = type->ctlr; | |
| 1992/0403 | if(bp->type == M_CTL){ | |
| 1992/0410 |
| |
| 1992/0403 |
| |
| 1992/0922 |
| |
| 1992/1222 | qlock(ctlr); if(streamparse("connect", bp)){ if(type->type == -1) ctlr->all--; type->type = strtol((char*)bp->rptr, 0, 0); if(type->type == -1) ctlr->all++; } | |
| 1992/0403 | else if(streamparse("promiscuous", bp)) { | |
| 1992/0410 |
| |
| 1992/0424 |
| |
| 1992/1222 | type->prom = 1; ctlr->prom++; if(ctlr->prom == 1) (*ctlr->board->mode)(ctlr, 1); | |
| 1992/0403 | } | |
| 1992/1222 | qunlock(ctlr); | |
| 1992/0403 | freeb(bp); return; } | |
| 1992/0922 |
| |
| 1992/0424 | ||
| 1992/0403 | /* | |
| 1992/1222 | * Give packet a local address, return upstream if destined for | |
| 1992/0403 | * this machine. */ | |
| 1992/0406 | if(BLEN(bp) < ETHERHDRSIZE && (bp = pullup(bp, ETHERHDRSIZE)) == 0) return; | |
| 1992/0922 |
| |
| 1992/0406 |
| |
| 1992/1222 | pkt = (Etherpkt*)bp->rptr; memmove(pkt->s, ctlr->ea, sizeof(ctlr->ea)); if(memcmp(ctlr->ea, pkt->d, sizeof(ctlr->ea)) == 0){ | |
| 1992/0403 | len = blen(bp); | |
| 1992/0406 |
| |
| 1992/0424 |
| |
| 1992/0406 |
| |
| 1992/1222 | if(bp = expandb(bp, len >= ETHERMINTU ? len: ETHERMINTU)){ putq(&ctlr->lbq, bp); wakeup(&ctlr->rr); | |
| 1992/0403 | } return; } | |
| 1992/0406 |
| |
| 1992/1222 | if(memcmp(ctlr->ba, pkt->d, sizeof(ctlr->ba)) == 0 || ctlr->prom || ctlr->all){ | |
| 1992/0403 | len = blen(bp); nbp = copyb(bp, len); | |
| 1992/0406 | if(nbp = expandb(nbp, len >= ETHERMINTU ? len: ETHERMINTU)){ | |
| 1992/0403 | nbp->wptr = nbp->rptr+len; | |
| 1992/0424 |
| |
| 1992/0406 |
| |
| 1992/1222 | putq(&ctlr->lbq, nbp); wakeup(&ctlr->rr); | |
| 1992/0403 | } } /* | |
| 1992/1222 | * Only one transmitter at a time. | |
| 1992/0403 | */ | |
| 1992/0424 |
| |
| 1992/1222 | qlock(&ctlr->tlock); | |
| 1992/0403 | if(waserror()){ | |
| 1992/0411 | freeb(bp); | |
| 1992/0424 |
| |
| 1992/1222 | qunlock(&ctlr->tlock); | |
| 1992/0403 | nexterror(); } /* | |
| 1992/0424 |
| |
| 1992/1222 | * Wait till we get an output buffer. | |
| 1992/0424 | * should try to restart. | |
| 1992/0403 | */ | |
| 1992/0424 |
| |
| 1992/1222 | sleep(&ctlr->tr, isobuf, ctlr); | |
| 1992/0403 | ||
| 1992/0424 |
| |
| 1992/1222 | ring = &ctlr->tb[ctlr->th]; | |
| 1992/0424 | ||
| 1992/0403 | /* | |
| 1992/1222 | * Copy message into buffer. | |
| 1992/0403 | */ len = 0; for(nbp = bp; nbp; nbp = nbp->next){ if(sizeof(Etherpkt) - len >= (n = BLEN(nbp))){ | |
| 1992/0501 |
| |
| 1992/1222 | memmove(ring->pkt+len, nbp->rptr, n); | |
| 1992/0403 | len += n; | |
| 1992/1222 | } | |
| 1992/0403 | if(bp->flags & S_DELIM) break; } /* | |
| 1992/0407 |
| |
| 1992/1222 | * Pad the packet (zero the pad). | |
| 1992/0403 | */ if(len < ETHERMINTU){ | |
| 1992/0501 |
| |
| 1992/1222 | memset(ring->pkt+len, 0, ETHERMINTU-len); | |
| 1992/0403 | len = ETHERMINTU; } /* | |
| 1992/0424 |
| |
| 1992/0407 |
| |
| 1992/1222 | * Set up the transmit buffer and * start the transmission. | |
| 1992/0403 | */ | |
| 1992/0424 |
| |
| 1992/1222 | ctlr->outpackets++; ring->len = len; ring->owner = Interface; ctlr->th = NEXT(ctlr->th, ctlr->ntb); (*ctlr->board->transmit)(ctlr); | |
| 1992/0403 | freeb(bp); | |
| 1992/0424 |
| |
| 1992/1222 | qunlock(&ctlr->tlock); | |
| 1992/0403 | poperror(); } /* | |
| 1992/1222 | * Open an ether line discipline. | |
| 1992/0403 | */ static void etherstopen(Queue *q, Stream *s) { | |
| 1992/0922 |
| |
| 1992/1222 | Ctlr *ctlr = softctlr[0]; Type *type; | |
| 1992/0403 | ||
| 1992/0410 |
| |
| 1992/1222 | type = &ctlr->type[s->id]; RD(q)->ptr = WR(q)->ptr = type; type->type = 0; type->q = RD(q); type->inuse = 1; type->ctlr = ctlr; | |
| 1992/0403 | } /* | |
| 1992/1222 | * Close ether line discipline. | |
| 1992/0403 | * | |
| 1992/1222 | * The locking is to synchronize changing the ethertype with * sending packets up the stream on interrupts. | |
| 1992/0403 | */ | |
| 1992/1222 | static int isclosed(void *arg) { return ((Type*)arg)->q == 0; } | |
| 1992/0403 | static void etherstclose(Queue *q) { | |
| 1992/0922 |
| |
| 1992/1222 | Type *type = (Type*)(q->ptr); Ctlr *ctlr = type->ctlr; | |
| 1992/0403 | ||
| 1992/0922 |
| |
| 1992/0424 |
| |
| 1992/0410 |
| |
| 1992/0625 |
| |
| 1992/0505 |
| |
| 1992/0410 |
| |
| 1992/1222 | if(type->prom){ qlock(ctlr); ctlr->prom--; if(ctlr->prom == 0) (*ctlr->board->mode)(ctlr, 0); qunlock(ctlr); } if(type->type == -1){ qlock(ctlr); ctlr->all--; qunlock(ctlr); } /* * Mark as closing and wait for kproc * to close us. */ lock(&ctlr->clock); type->clist = ctlr->clist; ctlr->clist = type; unlock(&ctlr->clock); wakeup(&ctlr->rr); sleep(&type->cr, isclosed, type); type->type = 0; type->prom = 0; type->inuse = 0; netdisown(type); type->ctlr = 0; | |
| 1992/0403 | } static Qinfo info = { | |
| 1992/1015/sys/src/9/pc/devether.c:276,295 – 1992/1222/sys/src/9/pc/devether.c:305,324 | ||
| 1992/0403 | static int | |
| 1992/0404 | clonecon(Chan *c) | |
| 1992/0403 | { | |
| 1992/0922 |
| |
| 1992/1222 | Ctlr *ctlr = softctlr[0]; Type *type; | |
| 1992/0403 | ||
| 1992/0711 | USED(c); | |
| 1992/0410 |
| |
| 1992/1222 | for(type = ctlr->type; type < &ctlr->type[NType]; type++){ qlock(type); if(type->inuse || type->q){ qunlock(type); | |
| 1992/0403 | continue; } | |
| 1992/0410 |
| |
| 1992/0625 |
| |
| 1992/0410 |
| |
| 1992/1222 | type->inuse = 1; netown(type, u->p->user, 0); qunlock(type); return type - ctlr->type; | |
| 1992/0403 | } exhausted("ether channels"); | |
| 1992/0711 | return 0; | |
| 1992/1015/sys/src/9/pc/devether.c:298,311 – 1992/1222/sys/src/9/pc/devether.c:327,341 | ||
| 1992/0403 | static void | |
| 1992/0404 | statsfill(Chan *c, char *p, int n) | |
| 1992/0403 | { | |
| 1992/0922 |
| |
| 1992/1222 | Ctlr *ctlr = softctlr[0]; | |
| 1992/0403 | char buf[256]; | |
| 1992/0711 | USED(c); | |
| 1992/0403 | sprint(buf, "in: %d\nout: %d\ncrc errs %d\noverflows: %d\nframe errs %d\nbuff errs: %d\noerrs %d\naddr: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x\n", | |
| 1992/0404 |
| |
| 1992/1222 | ctlr->inpackets, ctlr->outpackets, ctlr->crcs, ctlr->overflows, ctlr->frames, ctlr->buffs, ctlr->oerrs, ctlr->ea[0], ctlr->ea[1], ctlr->ea[2], ctlr->ea[3], ctlr->ea[4], ctlr->ea[5]); | |
| 1992/0403 | strncpy(p, buf, n); } | |
| 1992/1015/sys/src/9/pc/devether.c:313,367 – 1992/1222/sys/src/9/pc/devether.c:343,390 | ||
| 1992/0403 | typefill(Chan *c, char *p, int n) { char buf[16]; | |
| 1992/0922 |
| |
| 1992/1222 | Type *type; | |
| 1992/0403 | ||
| 1992/0410 |
| |
| 1992/1222 | type = &softctlr[0]->type[STREAMID(c->qid.path)]; sprint(buf, "%d", type->type); | |
| 1992/0403 | strncpy(p, buf, n); } static void | |
| 1992/0922 |
| |
| 1992/1222 | etherup(Ctlr *ctlr, Etherpkt *pkt, int len) | |
| 1992/0403 | { | |
| 1992/0501 |
| |
| 1992/0404 | int t; | |
| 1992/0922 |
| |
| 1992/1222 | Type *type; | |
| 1992/0501 | Block *bp; | |
| 1992/0404 | ||
| 1992/0501 |
| |
| 1992/0410 |
| |
| 1992/0404 |
| |
| 1992/0410 |
| |
| 1992/0404 |
| |
| 1992/1222 | t = (pkt->type[0]<<8)|pkt->type[1]; for(type = &ctlr->type[0]; type < &ctlr->type[NType]; type++){ | |
| 1992/0404 | /* | |
| 1992/1222 | * Check for open, the right type, and flow control. | |
| 1992/0404 | */ | |
| 1992/0410 |
| |
| 1992/1222 | if(type->q == 0) | |
| 1992/0404 | continue; | |
| 1992/1222 | if(t != type->type && type->type != -1) continue; if(type->q->next->len > Streamhi) continue; | |
| 1992/0404 | /* | |
| 1992/1222 | * Only a trace channel gets packets destined for other machines. | |
| 1992/0404 | */ | |
| 1992/0410 |
| |
| 1992/1222 | if(type->type != -1 && pkt->d[0] != 0xFF && (*pkt->d != *ctlr->ea || memcmp(pkt->d, ctlr->ea, sizeof(pkt->d)))) | |
| 1992/0404 | continue; | |
| 1992/0410 |
| |
| 1992/0404 |
| |
| 1992/1015 |
| |
| 1992/1222 | if(waserror() == 0){ | |
| 1992/0424 | bp = allocb(len); | |
| 1992/1222 | memmove(bp->rptr, pkt, len); | |
| 1992/0424 | bp->wptr += len; | |
| 1992/0404 | bp->flags |= S_DELIM; | |
| 1992/0410 |
| |
| 1992/1222 | PUTNEXT(type->q, bp); | |
| 1992/1015 | poperror(); | |
| 1992/0404 | } | |
| 1992/0410 |
| |
| 1992/0404 | } } | |
| 1992/1015/sys/src/9/pc/devether.c:368,417 – 1992/1222/sys/src/9/pc/devether.c:391,456 | ||
| 1992/0403 | static int isinput(void *arg) { | |
| 1992/0922 |
| |
| 1992/1222 | Ctlr *ctlr = arg; | |
| 1992/0403 | ||
| 1992/0925 |
| |
| 1992/1222 | return ctlr->lbq.first || ctlr->rb[ctlr->rh].owner == Host || ctlr->clist; | |
| 1992/0403 | } static void etherkproc(void *arg) { | |
| 1992/0922 |
| |
| 1992/1222 | Ctlr *ctlr = arg; RingBuf *ring; | |
| 1992/0404 | Block *bp; | |
| 1992/1222 | Type *type; | |
| 1992/0403 | if(waserror()){ | |
| 1992/0404 |
| |
| 1992/0922 |
| |
| 1992/0404 |
| |
| 1992/1222 | print("%s noted\n", ctlr->name); /* fix if(ctlr->board->reset) (*ctlr->board->reset)(ctlr); */ ctlr->kproc = 0; | |
| 1992/0403 | nexterror(); } | |
| 1992/0404 |
| |
| 1992/1222 | ||
| 1992/0403 | for(;;){ | |
| 1992/0915 |
| |
| 1992/0922 |
| |
| 1992/1222 | tsleep(&ctlr->rr, isinput, ctlr, 500); if(ctlr->board->watch) (*ctlr->board->watch)(ctlr); | |
| 1992/0424 | ||
| 1992/0406 | /* | |
| 1992/1222 | * Process any internal loopback packets. | |
| 1992/0406 | */ | |
| 1992/0424 |
| |
| 1992/0404 |
| |
| 1992/0501 |
| |
| 1992/1222 | while(bp = getq(&ctlr->lbq)){ ctlr->inpackets++; etherup(ctlr, (Etherpkt*)bp->rptr, BLEN(bp)); | |
| 1992/0404 | freeb(bp); } | |
| 1992/0408 | ||
| 1992/0406 | /* | |
| 1992/1222 | * Process any received packets. | |
| 1992/0406 | */ | |
| 1992/0424 |
| |
| 1992/0406 |
| |
| 1992/0424 |
| |
| 1992/0501 |
| |
| 1992/0424 |
| |
| 1992/0502 |
| |
| 1992/1222 | while(ctlr->rb[ctlr->rh].owner == Host){ ctlr->inpackets++; ring = &ctlr->rb[ctlr->rh]; etherup(ctlr, (Etherpkt*)ring->pkt, ring->len); ring->owner = Interface; ctlr->rh = NEXT(ctlr->rh, ctlr->nrb); | |
| 1992/0424 | } | |
| 1992/1222 | /* * Close Types requesting it. */ if(ctlr->clist){ lock(&ctlr->clock); for(type = ctlr->clist; type; type = type->clist){ type->q = 0; wakeup(&type->cr); } ctlr->clist = 0; unlock(&ctlr->clock); } | |
| 1992/0424 | } } | |
| 1992/0410 | ||
| 1992/1015/sys/src/9/pc/devether.c:418,463 – 1992/1222/sys/src/9/pc/devether.c:457,520 | ||
| 1992/0922 | static void etherintr(Ureg *ur) { | |
| 1992/1222 | Ctlr *ctlr = softctlr[0]; | |
| 1992/0922 | USED(ur); | |
| 1992/1222 | (*ctlr->board->intr)(ctlr); | |
| 1992/0922 | } | |
| 1992/0424 | void etherreset(void) { | |
| 1992/0922 |
| |
| 1992/1222 | Ctlr *ctlr; Board **board; | |
| 1992/0625 | int i; | |
| 1992/0410 | ||
| 1992/0625 |
| |
| 1992/0922 |
| |
| 1992/1222 | if(softctlr[nctlr] == 0) softctlr[nctlr] = xalloc(sizeof(Ctlr)); ctlr = softctlr[nctlr]; for(board = boards; *board; board++){ ctlr->board = *board; if((*ctlr->board->reset)(ctlr) == 0){ ctlr->present = 1; /* * IRQ2 doesn't really exist, it's used to gang the interrupt * controllers together. A device set to IRQ2 will appear on * the second interrupt controller as IRQ9. */ if(ctlr->board->irq == 2) ctlr->board->irq = 9; setvec(Int0vec + ctlr->board->irq, etherintr); | |
| 1992/0922 | break; } | |
| 1992/0917 | } | |
| 1992/0922 |
| |
| 1992/1222 | if(ctlr->present == 0) | |
| 1992/0922 | return; | |
| 1992/1222 | nctlr++; | |
| 1992/0410 | ||
| 1992/0424 |
| |
| 1992/1222 | if(ctlr->nrb == 0) ctlr->nrb = Nrb; ctlr->rb = xalloc(sizeof(RingBuf)*ctlr->nrb); if(ctlr->ntb == 0) ctlr->ntb = Ntb; ctlr->tb = xalloc(sizeof(RingBuf)*ctlr->ntb); | |
| 1992/0410 | ||
| 1992/0424 |
| |
| 1992/1222 | memset(ctlr->ba, 0xFF, sizeof(ctlr->ba)); ctlr->net.name = "ether"; ctlr->net.nconv = NType; ctlr->net.devp = &info; ctlr->net.protop = 0; ctlr->net.listen = 0; ctlr->net.clone = clonecon; ctlr->net.ninfo = 2; ctlr->net.info[0].name = "stats"; ctlr->net.info[0].fill = statsfill; ctlr->net.info[1].name = "type"; ctlr->net.info[1].fill = typefill; | |
| 1992/0625 | for(i = 0; i < NType; i++) | |
| 1992/1222 | netadd(&ctlr->net, &ctlr->type[i], i); | |
| 1992/0403 | } | |
| 1992/0425 | void | |
| 1992/1015/sys/src/9/pc/devether.c:464,492 – 1992/1222/sys/src/9/pc/devether.c:521,561 | ||
| 1992/0425 | etherinit(void) | |
| 1992/0403 | { int ctlrno = 0; | |
| 1992/0922 |
| |
| 1992/1222 | Ctlr *ctlr = softctlr[ctlrno]; | |
| 1992/0424 | int i; | |
| 1992/0403 | ||
| 1992/0917 |
| |
| 1992/1222 | if(ctlr->present == 0) | |
| 1992/0917 | return; | |
| 1992/0424 |
| |
| 1992/1222 | ctlr->rh = 0; ctlr->ri = 0; for(i = 0; i < ctlr->nrb; i++) ctlr->rb[i].owner = Interface; | |
| 1992/0424 |
| |
| 1992/1222 | ctlr->th = 0; ctlr->ti = 0; for(i = 0; i < ctlr->ntb; i++) ctlr->tb[i].owner = Host; } | |
| 1992/0424 | ||
| 1992/1222 | Chan* etherattach(char *spec) { int ctlrno = 0; Ctlr *ctlr = softctlr[ctlrno]; if(ctlr->present == 0) error(Enodev); | |
| 1992/0403 | /* | |
| 1992/1222 | * Enable the interface * and start the kproc. | |
| 1992/0501 | */ | |
| 1992/0424 |
| |
| 1992/1222 | (*ctlr->board->attach)(ctlr); if(ctlr->kproc == 0){ sprint(ctlr->name, "ether%dkproc", ctlrno); ctlr->kproc = 1; kproc(ctlr->name, etherkproc, ctlr); | |
| 1992/0403 | } | |
| 1992/1222 | return devattach('l', spec); | |
| 1992/0403 | } | |