📄 if_es.c
字号:
/* call input hook if any */ if ((etherInputHookRtn != NULL) && (* etherInputHookRtn) (&ls->ls_if, (char *)eh, len)) return (OK);#ifdef BSD43_DRIVER /* This legacy code is not correct for the BSD 4.4 stack. It would * also treat multicast addresses like alien packets, and not send * them up the stack. The higher-level protocols in the new stack * can handle these addresses, and will discard them if they do not * match an existing multicast group. */ /* do software filter if controller is in promiscuous mode */ if (ls->ls_flags & LS_PROMISCUOUS_FLAG) if ( (bcmp ( (char *)eh->ether_dhost, /* not our adrs? */ (char *)ls->ls_enaddr, sizeof (eh->ether_dhost)) != 0) && (bcmp ( (char *)eh->ether_dhost, /* not broadcast? */ (char *)etherbroadcastaddr, sizeof (eh->ether_dhost)) != 0)) return (OK);#endif if (len >= sizeof (struct ether_header)) len -= sizeof (struct ether_header); else len = 0; pData = ((u_char *) eh) + (sizeof (struct ether_header));#ifdef BSD43_DRIVER check_trailer (eh, pData, &len, &off, &ls->ls_if); if (len == 0) return (OK); ether_type = eh->ether_type;#endif m = NULL; /* we can loan out receive buffers from ESTAR receive ring if: * * 1) canLoanRmd is TRUE. canLoanRmd is set to TRUE if memWidth * is NONE (no special restriction in copying data in terms of * size and boundary conditions) and each of the buffers in the * ESTAR ring is big enough to hold the maximum sized ethernet * frame (data-chaining is not being used for the input). * 2) trailer protocol is not being used for the given input ethernet frame. * 3) there is available free buffers that can be used to replace the * rbuf to be loaned out in the free list 'freeBufs'. * 4) size of the input ethernet frame is large enough to be used with * clustering. */ if (ls->canLoanRmds && off == 0 && ls->nFree > 0 && USE_CLUSTER (len)) { m = build_cluster (pData, len, &ls->ls_if, MC_LANCE, &(ls->loanRefCnt [ls->ls_rindex]), (FUNCPTR)esRmdFree, (int) ls, (int) eh, NULL); if (m != NULL) { FAST char *pBuf; /* get a free buffer from the free list to replace the * rbuf loaned out. replace the rbuf pointers in the RMD * to point to the new buffer. */ pBuf = ls->freeBufs [--ls->nFree]; rmd->rbuf_ladr = (u_short) ((int) pBuf & 0xff); rmd->es_rmd1.es_rmd1b = (rmd->es_rmd1.es_rmd1b & ~esrmd1_HADR) | (((int) pBuf >> 16) & esrmd1_HADR); } } if (m == NULL)#ifdef BSD43_DRIVER /* Instead of calling copy_to_mbufs (), we call bcopy_to_mbufs () * with ls->memWidth as an addtional argument to specify unit of a * copy op. * * Most drivers would use macro copy_to_mbufs (), which will in turn * call bcopy_to_mbufs () telling it to use the normal bcopy (). Some * of the on-board ESTAR hardware implementations require that you * copy the data by certain number of bytes from dedicated memory * to system memory, so ESTAR driver has a es_bcopy () routine that * conforms to this requirement. */ m = bcopy_to_mbufs (pData, len, off, (struct ifnet *) &ls->ls_if, ls->memWidth);#else m = bcopy_to_mbufs (pData, len, 0, &ls->ls_if, ls->memWidth);#endif if (m == NULL) ++ls->ls_if.if_ierrors; /* bump error counter */ else#ifdef BSD43_DRIVER do_protocol_with_type (ether_type, m, &ls->ls_ac, len);#else do_protocol (eh, m, &ls->ls_ac, len);#endif return (OK); }#ifdef BSD43_DRIVER/********************************************************************************* esOutput - Ethernet output routine** Ethernet output routine.* Encapsulate a packet of type family for the local net.* Use trailer local net encapsulation if enough data in first* packet leaves a multiple of 512 bytes of data in remainder.*/LOCAL int esOutput ( FAST struct ifnet *ifp, FAST struct mbuf *m0, struct sockaddr *dst ) { return (ether_output (ifp, m0, dst, (FUNCPTR) esStartOutput, &ls_softc [ifp->if_unit]->ls_ac)); }#endif/********************************************************************************* esStartOutput - start pending output** Start output to ESTAR.* Queue up all pending datagrams for which transmit buffers are available.* Kick start the transmitter to avoid the polling interval latency.* This routine is called by esInit (). With BSD 4.3 drivers, it is also called* by esOutput (). BSD 4.4 drivers use a slightly different model in which it* is called directly from the generic ether_output() routine.* It is very important that this routine be executed with splimp set.* If this is not done, another task could allocate the same tmd!*/#ifdef BSD43_DRIVERLOCAL VOID esStartOutput ( int unit ) { FAST struct ls_softc *ls = ls_softc [unit];#elseLOCAL VOID esStartOutput ( struct ls_softc * ls ) {#endif FAST struct mbuf *m; FAST es_tmd *tmd; char *buf, *buf0; u_short *temp, temp1; FAST int len, i; FAST int sx; FAST int oldLevel; ES_DEVICE *dv; sx = splimp (); dv = ls->devAdrs; ls->ls_flags |= LS_START_OUTPUT_FLAG; /* Loop placing message buffers in output ring until no more or no room */ while (ls->ls_if.if_snd.ifq_head != NULL) { /* there is something to send */ if ((tmd = esGetFreeTMD (ls)) == NULL) /* get a transmit buffer */ break; IF_DEQUEUE (&ls->ls_if.if_snd, m); /* get head of next mbuf chain */ buf = (char *) ( (u_int) ls->tmd_ring.t_bufs + (u_int) ( ( ( (u_int)tmd - (u_int)ls->ls_tring) / sizeof (es_tmd)) * ls->bufSize)); buf0 = buf; /* copy packet to write buffer */ temp = (u_short *)buf;#ifdef BSD43_DRIVER bcopy_from_mbufs (buf, m, len, ls->memWidth);#else bcopy_from_mbufs (buf, m, len, ls->memWidth);#endif len = max (ETHERSMALL, len); buf += len; /* call output hook if any */ if ((etherOutputHookRtn != NULL) && (* etherOutputHookRtn) (&ls->ls_if, buf, len)) continue; /* place a transmit request */ oldLevel = intLock (); /* disable ints during update */ tmd->tbuf_tmd3 = 0; /* clear buffer error status */ tmd->tbuf_bcnt = -len; /* negative message byte count */ tmd->es_tmd1.es_tmd1b |= estmd1_ENP; /* buffer is end of packet */ tmd->es_tmd1.es_tmd1b |= estmd1_STP; /* buffer is start of packet */ tmd->es_tmd1.es_tmd1b &= ~estmd1_DEF; /* clear status bit */ tmd->es_tmd1.es_tmd1b &= ~estmd1_MORE; tmd->es_tmd1.es_tmd1b &= ~estmd1_ERR; /* try to output here */ *dlan.dlcr1 = 0; /* disable ints during update */ i=0; /* extract the buffer */ if (newdlan == TRUE) { while (i*2 < len) { if (i*2 < (buf - buf0)) dv->bmpr0 = *temp++; else dv->bmpr0 = 0; i += 1; } temp1 = (u_short)((len>>8) | (len<<8) | 0x80); /* set TMST */ dv->bmpr2 = temp1; } else { while (i*2 < len) { if (i*2 < (buf - buf0)) { dv->bmpr0 = (*temp>>8 | *temp<<8); temp++; } else dv->bmpr0 = 0; i += 1; } dv->bmpr2 = (u_short)(len | 0x8000); /* set TMST */ } while ( (*dlan.dlcr0 & es_tmt_ok) == es_tmt_ok) ; intUnlock (oldLevel); /* now esInt won't get confused */ ls->ls_tindex = (ls->ls_tindex + 1) & (ls->ls_tsize - 1);#ifndef BSD43_DRIVER /* BSD 4.4 ether_output() doesn't bump statistic. */ ls->ls_if.if_opackets++;#endif } ls->ls_flags &= ~LS_START_OUTPUT_FLAG; *dlan.dlcr1 = ES_TMT_MASK; /* set transmit interrupt mask */ splx (sx); }/********************************************************************************* esIoctl - Process an ioctl request** Process an ioctl request.*/LOCAL int esIoctl ( FAST struct ifnet *ifp, int cmd, caddr_t data ) { int unit = ifp->if_unit; FAST struct ls_softc *ls = ls_softc [unit]; int s = splimp (); int error = 0; switch (cmd) { case SIOCSIFADDR: ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN (data)->sin_addr; arpwhohas (ifp, &IA_SIN (data)->sin_addr); break; case SIOCGIFADDR: bcopy((caddr_t) ls->ls_enaddr, (caddr_t) ((struct ifreq *)data)->ifr_addr.sa_data, 6); break; case SIOCGIFFLAGS: *(short *)data = ifp->if_flags; break; case SIOCSIFFLAGS: ls->ls_if.if_flags = ifp->if_flags; if (ifp->if_flags & IFF_PROMISC) ls->ls_flags |= LS_PROMISCUOUS_FLAG; else ls->ls_flags &= ~LS_PROMISCUOUS_FLAG; if (ifp->if_flags & IFF_UP) ls->ls_if.if_flags |= (IFF_UP|IFF_RUNNING); else ls->ls_if.if_flags &= ~(IFF_UP|IFF_RUNNING); break; default: error = EINVAL; } splx (s); return (error); }/********************************************************************************* esChipReset - hardware reset of chip (stop it)*/LOCAL VOID esChipReset ( struct ls_softc *ls ) { *dlan.dlcr1 = 0; /* reset transmit interrupt mask */ *dlan.dlcr3 = 0; /* reset receive interrupt mask */ *dlan.dlcr6 = es_ena_dlc; /* stop the etherstar */ *dlan.dlcr2 = 0xcf; /* clear interrupts */ *dlan.dlcr0 = 0x0f; }/********************************************************************************* esChipInit - hardware init of chip (init & start it)*/LOCAL VOID esChipInit ( FAST struct ls_softc *ls ) { u_short temp; FAST ES_DEVICE *dv = ls->devAdrs; /* setup vector */ dv->eth_vector = ls->ivec; *dlan.dlcr6 = es_ena_dlc; /* stop the etherstar */ *dlan.dlcr2 = 0xcf; /* clear all receive errors */ *dlan.dlcr3 = 0x8f; /* reset receive interrupt mask */ *dlan.dlcr0 = 0x0f; /* clear all transmit errors */ *dlan.dlcr1 = 0x00; /* reset transmit interrupt mask */ /* flush the receive buffer memory of the etherstar */ temp = esReadBmpr0 (dv); while ( !(*dlan.dlcr5 & 0x40) ) temp = esReadBmpr0 (dv); temp = esReadBmpr0 (dv); temp = esReadBmpr0 (dv); /* configure etherstar in normal mode */ *dlan.dlcr4 = es_lbc; /* loopback disabled, byte swap enabled */ *dlan.dlcr5 = 0x02; /* physical, multicast and broadcast */ /* copy the enet address into the softc */ *dlan.dlcr8 = esEnetAddr[0]; *dlan.dlcr9 = esEnetAddr[1]; /* setting these registers is only */ *dlan.dlcr10 = esEnetAddr[2]; /* possible when etherstar is stopped */ *dlan.dlcr11 = esEnetAddr[3]; *dlan.dlcr12 = esEnetAddr[4]; *dlan.dlcr13 = esEnetAddr[5]; for ( temp = 20000; temp > 0; temp-- ); /* start chip */ *dlan.dlcr6 = 0x00; /* start the etherstar */ *dlan.dlcr1 = ES_TMT_MASK; /* set transmit interrupt mask */ *dlan.dlcr3 = ES_RCV_MASK; /* set receive interrupt mask */ }/********************************************************************************* esGetFreeTMD - get next available TMD*/LOCAL es_tmd *esGetFreeTMD ( FAST struct ls_softc *ls ) { FAST es_tmd *tmd; /* check if buffer is available (owned by host) */ /* also check for tindex overrun onto dindex */ tmd = ls->ls_tring + ls->ls_tindex; if (((tmd->es_tmd1.es_tmd1b & estmd1_OWN) != 0) || (((ls->ls_tindex + 1) & (ls->ls_tsize - 1)) == ls->ls_dindex)) tmd = (es_tmd *) NULL; return (tmd); }/********************************************************************************* esGetFullRMD - get next received message RMD*/LOCAL es_rmd *esGetFullRMD ( FAST struct ls_softc *ls ) { FAST es_rmd *rmd; /* check if buffer is full (owned by host) */ rmd = ls->ls_rring + ls->ls_rindex; if ((rmd->es_rmd1.es_rmd1b & esrmd1_OWN) == 0) return (rmd); else return ((es_rmd *) NULL); }/********************************************************************************* esRmdFree - called when loaned out rbuf is freed by MCLFREE.** Puts the loaned out rbuf into free list to be reused as loan replacements.*/LOCAL VOID esRmdFree ( FAST struct ls_softc *ls, FAST char *pBuf ) { ls->freeBufs [ls->nFree++] = pBuf; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -