/* 调用通用以太网初始化例程 */ dprintf(("Attaching interface...n")); ether_ifattach(ifp, ETHER_BPF_SUPPORTED); /* 在if_ethersubr.c中的ether_ifattach例程 void ether_ifattach(ifp, bpf) 调用时,ETHER_BPF_SUPPORTED是BSD的包过滤器,如果在编译时设置文件没有打开包过滤器,那么代表0,否则是1 register struct ifnet *ifp; int bpf; { register struct ifaddr *ifa; register struct sockaddr_dl *sdl; if_attach(ifp); 此例程在if.c 中 ifp->if_type = IFT_ETHER;代表以太网 ifp->if_addrlen = 6;硬件地址长度是6 ifp->if_hdrlen = 14;包的头长度是6+6+2=14,其中2是协议类型 ifp->if_mtu = ETHERMTU; 为1500,多此一举,在前面你可看到,已经填充了. ifp->if_resolvemulti = ether_resolvemulti; 以太网解析多播例程指针 if (ifp->if_baudrate == 0) 波特率 ifp->if_baudrate = 10000000; ifa = ifnet_addrs[ifp->if_index - 1];在ifnet_addrs[]数组中找到本地址指针 KASSERT(ifa != NULL, ("%s: no lladdr!n", __FUNCTION__)); sdl = (struct sockaddr_dl *)ifa->ifa_addr; ifa->ifa_addr在此时指向的是sockaddr_dl结构. sdl->sdl_type = IFT_ETHER; sdl->sdl_alen = ifp->if_addrlen; bcopy((IFP2AC(ifp))->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);把硬件地址拷贝到sdl结构中if (bpf) bpf为真,即加入了BSD包过滤 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); if (ng_ether_attach_p != NULL) (*ng_ether_attach_p)(ifp); } */ printf("el%d: 3c501 address mn",idev->id_unit, sc->arpcom.ac_enaddr, ":"); dprintf(("el_attach() finished.n")); return(1); } /* 该例程重设接口. 在el_watchdog()中调用,因为watchdog不在本驱动程序中支持,所以从不被调用*/ static void el_reset(xsc)/*上面的一个函数,重设硬件*/ void *xsc; { struct el_softc *sc = xsc; int s; dprintf(("elreset()n")); s = splimp();/*关网络中断*/ el_stop(sc);/*下面的一个函数*/ el_init(sc);/*重新初始化卡*/ splx(s);/*开网络中断*/ } /*停止接口,在el_ioctl()和el_reset()中调用*/ static void el_stop(xsc) void *xsc; { struct el_softc *sc = xsc; outb(sc->el_base+EL_AC,0);/*用0写辅助命令寄存器*/ } /* 初始化接口. */ static void el_init(xsc) void *xsc; { struct el_softc *sc = xsc; struct ifnet *ifp; int s; u_short base; ifp = &sc->arpcom.ac_if;/*定位ifnet结构*/ base = sc->el_base;/*网卡基本I/O地址*/ /* 如果地址不知道,什么也不做. */ if(TAILQ_EMPTY(&ifp->if_addrhead)) /* 在if.c中的if_attach例程中已经填充,由el_attach调用 ether_attach时再调用if_attach */ return; s = splimp();/*关网络中断*/
/* 重设板卡. */ dprintf(("Resetting board...n")); el_hardreset(sc);/*该函数在上面,重设硬件*/ /* 设置接收寄存器 rx */ dprintf(("Configuring rx...n")); if(ifp->if_flags & IFF_PROMISC) /*是混杂模式?EL_RXC是0X6接收命令寄存器*/ outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW)); else outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW)); outb(base+EL_RBC,0);/*接收缓冲寄存器清0*/ /* 设置传输寄存器 TX */ dprintf(("Configuring tx...n")); outb(base+EL_TXC,0); /* 开始接收 */ dprintf(("Starting reception...n")); outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));/*EL_AC_IRQE是IRQ enable(可用) EL_AC_RX为接收寄存器*/ /* 设置一些开始使用的标志 */ ifp->if_flags |= IFF_RUNNING;/*加上正在运行标志*/ ifp->if_flags &= ~IFF_OACTIVE;/*去掉正在传输标志*/ /* 调用输出. */ el_start(ifp); splx(s);/*开网络中断*/ |