⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_snnew.c

📁 T-kernel Tcp/ip Protocol Stack Sample
💻 C
📖 第 1 页 / 共 5 页
字号:
#endif
	ifp->if_softc = sc;
	ifp->if_unit = is->id_unit;
	ifp->if_name = "sn";
	ifp->if_mtu = ETHERMTU;
	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
	ifp->if_init = sninit;
	ifp->if_output = ether_output;
	ifp->if_start = snstart;
	ifp->if_ioctl = snioctl;
	ifp->if_watchdog = snwatchdog;
	ifp->if_type = IFT_ETHER;
	ifp->if_addrlen = ETHER_ADDR_LEN;
	ifp->if_hdrlen = ETHER_HDR_LEN;
	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;

	ifp->if_timer = 0;

	if_attach(ifp);

	/*
	 * Fill the hardware address into ifa_addr if we find an AF_LINK entry.
	 * We need to do this so bpf's can get the hardware addr of this card.
	 * netstat likes this too!
	 */
	ifa = ifp->if_addrlist;
	while ((ifa != 0) && (ifa->ifa_addr != 0) &&
	       (ifa->ifa_addr->sa_family != AF_LINK))
	    ifa = ifa->ifa_next;

	if ((ifa != 0) && (ifa->ifa_addr != 0)) {
	    sdl = (struct sockaddr_dl *) ifa->ifa_addr;
	    sdl->sdl_type = IFT_ETHER;
	    sdl->sdl_alen = ETHER_ADDR_LEN;
	    sdl->sdl_slen = 0;
	    bcopy((char *)sc->arpcom.ac_enaddr, (char *)LLADDR(sdl), ETHER_ADDR_LEN);
	}

	snstop();

	return 1;
}

/*
 * Reset and initialize the chip
 */
void
sninit(void *dummy)
{
	register struct sn_softc *sc = &sn_softc0;
	register struct ifnet *ifp = &sc->arpcom.ac_if;
	int s;
	volatile unsigned int j;
	unsigned short i, ret;
#if defined(ORG)
	unsigned short flags, mask;
#else
	unsigned short flags;
	unsigned char mask;
#endif
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	volatile unsigned short tmp_reg;
#endif

	s = splimp();

	/* This resets the registers mostly to defaults, but doesn't
	 * affect EEPROM.  After the reset cycle, we pause briefly
	 * for the chip to be happy.
	 */
	SMC_SELECT_BANK( 0 );
	outw( BASE + RECV_CONTROL_REG_W, RCR_SOFTRESET );

	for (j=0;j<WAIT_UNIT;j++); /* BUSY wait */


	/* Terminate soft reset and disable transmit functionality */
	outw( BASE + RECV_CONTROL_REG_W, 0x0000 );
	SMC_DELAY( );
	SMC_DELAY( );

#if defined(_MIC_M32192_) || defined(_MIC_M32104_)
	/* Set NO_WAIT bit */
	SMC_SELECT_BANK( 1 );
	i = inw( BASE + CONFIG_REG_W );
	outw( BASE + CONFIG_REG_W, i|CR_NOW_WAIT_ST );
#endif

	/* Disable receive functionality */
	SMC_SELECT_BANK( 0 );
	outw( BASE + TXMIT_CONTROL_REG_W, 0x0000 );


	/* Set the control register to automatically release
	 * succesfully transmitted packets (making the best
	 * use out of our limited memory) and to enable the EPH
	 * interrupt on certain TX errors.
	 */
	SMC_SELECT_BANK( 1 );
	i = inw( BASE + CONTROL_REG_W );
	outw( BASE + CONTROL_REG_W, ( i|CTR_AUTO_RELEASE ));

	/* Reset the MMU and wait for it to be un-busy.
	 */
	SMC_SELECT_BANK( 2 );
	outw( BASE + MMU_CMD_REG_W, MMUCR_RESET );
	while ( inw( BASE + MMU_CMD_REG_W ) & MMUCR_BUSY ) /*NOTHING*/ ;


	/* Disable all interrupts
	 */
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	/* cannot access with byte length */
	outw( BASE + INTR_MASK_REG_W, 0x0000 );
#else
	outb( BASE + INTR_MASK_REG_B, 0x00 );
#endif


	/* Set the receiver filter.  We want receive enabled and auto
	 * strip of CRC from received packet.  If we are promiscuous
	 * then set that bit too.   We just get all multicast packets
	 * even if we only want them from particular groups.  This may
	 * be changed at some future point.
	 */
	SMC_SELECT_BANK( 0 );

	flags = RCR_ENABLE | RCR_STRIP_CRC | RCR_ALMUL;

	if (ifp->if_flags & IFF_PROMISC)
	    flags |= RCR_PROMISC;

	outw( BASE + RECV_CONTROL_REG_W, flags );


	/* Set the transmitter control.  We want it enabled.
	 */
	flags = TCR_ENABLE;
#if !defined(SW_PAD)
	/* I (GB) have been unlucky getting this to work.
	 */
	flags |= TCR_PAD_ENABLE;
#endif

#if !defined(OLD)
	/* set Switched Full Duplex mode */
	flags |= TCR_SWFDUP;
#endif

	outw( BASE + TXMIT_CONTROL_REG_W, flags );


	/* Now, enable interrupts
	 */
	SMC_SELECT_BANK( 2 );

	mask = IM_EPH_INT |
	       IM_RX_OVRN_INT |
	       IM_RCV_INT |
#if defined(LAN91C111)
	       IM_MDINT |
#endif
	       IM_TX_INT;

#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	/* cannot access with byte length */
	tmp_reg = (u_short)(mask << 8);
	outw( BASE + INTR_MASK_REG_W, tmp_reg );
#else
	outb( BASE + INTR_MASK_REG_B, mask );
#endif
	sc->intr_mask = mask;
	sc->pages_wanted = -1;

	/* Mark the interface running but not active.
	 */
	ifp->if_flags |= IFF_RUNNING;
	ifp->if_flags &= ~IFF_OACTIVE;

	/* Initialize PHY chip */
	ret = phy_init();

	/* Attempt to push out any waiting packets.
	 */
	snstart(ifp);

	splx(s);
}

void
snstart(struct ifnet *ifp)
{
	register struct sn_softc *sc = &sn_softc0;
	register u_int len;
	register struct mbuf *m;
	struct mbuf *top;
	int s, pad;
#if defined(ORG)
	int mask;
#else
	u_char mask;
#endif
	u_short length;
	u_short numPages;
	u_char packet_no;
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	volatile unsigned short tmp_reg, ptr_reg;
#endif
	int time_out;

	s = splimp();

	if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) {
	    splx(s);
	    return;
	}

	if (sc->pages_wanted != -1) {
	    splx(s);
#ifdef PRINTON
	    printf("sn%d: snstart() while memory allocation pending\n",
	           ifp->if_unit);
#endif
	    return;
	}

startagain:

	/* Sneak a peek at the next packet
	 */
	m = sc->arpcom.ac_if.if_snd.ifq_head;
	if (m == 0) {
	    splx(s);
	    return;
	}

	/* Compute the frame length and set pad to give an overall
	 * even number of bytes.  Below we assume that the packet
	 * length is even.
	 */
	for (len = 0, top = m; m; m = m->m_next)
	    len += m->m_len;

	pad = (len & 1);

	/*
	 * We drop packets that are too large. Perhaps we should truncate
	 * them instead?
	 */
	if (len + pad > ETHER_MAX_LEN) {
#ifdef PRINTON
	    printf("sn%d: large packet discarded (A)\n", ifp->if_unit);
#endif
	    ++sc->arpcom.ac_if.if_oerrors;
	    IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
	    m_freem(m);  /* splimp and splx call */
	    goto readcheck;
	}

#ifdef SW_PAD
	/* If HW padding is not turned on, then pad to
	 * ETHER_MIN_LEN.
	 */
	if (len < ETHER_MIN_LEN)
	   pad = ETHER_MIN_LEN - len;
#endif

	length = pad + len;

#if defined(LAN91C111)
	/* the size of "page" is 2048 byte */
	numPages = (length + 6) >> 11;
#else
	/*
	 * The MMU wants the number of pages to be the number of 256 byte
	 * 'pages', minus 1 (A packet can't ever have 0 pages.
	 * We also include space for the status word, byte count and
	 * control bytes in the allocation request.
	 */
	numPages = (length + 6) >> 8;
#endif

	/* Now, try to allocate the memory
	 */
	SMC_SELECT_BANK( 2 );
	outw( BASE + MMU_CMD_REG_W, MMUCR_ALLOC | numPages );

	/* Wait a short amount of time to see if the allocation request
	 * completes.  Otherwise, I enable the interrupt and wait for
	 * completion asyncronously.
	 */

	time_out = MEMORY_WAIT_TIME;
	do {
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	    /* cannot access with byte length */
	    tmp_reg = inw( BASE + INTR_STAT_REG_W );
	    if ( (u_char)(tmp_reg & 0x00FF) & IM_ALLOC_INT ) {
	        break;
		}
#else
	    if ( inb( BASE + INTR_STAT_REG_B ) & IM_ALLOC_INT ) {
	        break;
		}
#endif
	} while ( --time_out );

	if ( !time_out ) {

	    /* No memory now.  Oh well, wait until the chip finds
	     * memory later.   Remember how many pages we were asking
	     * for and enable the allocation completion interrupt.
	     * Also set a watchdog in case  we miss the interrupt.
	     * We mark the interface active since there is no point
	     * in attempting an snstart() until after the memory is
	     * available.
	     */
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	    /* cannot access with byte length */
	    tmp_reg = inw( BASE + INTR_MASK_REG_W );
	    mask = (u_char)(tmp_reg >> 8) | IM_ALLOC_INT;
	    tmp_reg = (u_short)(mask << 8);
	    outw( BASE + INTR_MASK_REG_W, tmp_reg );
#else
	    mask = inb( BASE + INTR_MASK_REG_B ) | IM_ALLOC_INT;
	    outb( BASE + INTR_MASK_REG_B, mask );
#endif
	    sc->intr_mask = mask;

	    sc->arpcom.ac_if.if_timer = 1;
	    sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
	    sc->pages_wanted = numPages;

	    splx(s);
	    return;
	}

	/* The memory allocation completed.  Check the results.
	 */
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	/* cannot access with byte length */
	tmp_reg = inw( BASE + ALLOC_RESULT_REG_W );
	packet_no = (u_char)(tmp_reg << 8);
#else
	packet_no = inb( BASE + ALLOC_RESULT_REG_B );
#endif
	if ( packet_no & ARR_FAILED ) {
#ifdef PRINTON
	    printf("sn%d: Memory allocation failed\n", ifp->if_unit);
#endif
	    goto startagain;
	}

	/* We have a packet number, so tell the card to use it.
	 */
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	/* cannot access with byte length */
	tmp_reg = (u_short)packet_no & 0x00FF;
	outw( BASE + PACKET_NUM_REG_W, tmp_reg );
#else
	outb( BASE + PACKET_NUM_REG_B, packet_no );
#endif

	/* Point to the beginning of the packet
	 */
	outw( BASE + POINTER_REG_W, PTR_AUTOINC | 0x0000 );

	/* Send the packet length (+6 for status, length and control byte)
	 * and the status word (set to zeros)
	 */
	outw( BASE + DATA_REG_W, 0 );
#ifdef CHECK_PRO
	outw( BASE + DATA_REG_W, 0x0042 );
#else
#if defined(OLD)
	outb( BASE + DATA_REG_B, (length + 6) & 0xFF );
	outb( BASE + DATA_REG_B, (length + 6) >> 8 );
#else
	outw( BASE + DATA_REG_W, (length + 6) );
#endif
#endif /* CHECK_PRO */

    /***********************************
     Set Data:
        b15                           b0
        +------------------------------+
      0 |Status Word (=0)              |
        +------------------------------+
      2 |(length+6)/256 |(length+6)%256|
        +------------------------------+
      4 |Data Area                     |
        +------------------------------+
        |                              |
        +------------------------------+
   2046 |Control Byte                  | Last Data Byte if odd.
    max +------------------------------+
    **********************************/

	/* Get the packet from the kernel.  This will include the
	 * Ethernet frame header, MAC Addresses etc.
	 */
	IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);

#ifdef CHECK_PRO
	outw( BASE + DATA_REG_W, 0xFFFF );      /* dst MAC addr */
	outw( BASE + DATA_REG_W, 0xFFFF );
	outw( BASE + DATA_REG_W, 0xFFFF );
	outw( BASE + DATA_REG_W, 0x0000 );      /* src MAC addr */
	outw( BASE + DATA_REG_W, 0x6BE1 );
	outw( BASE + DATA_REG_W, 0xDE39 );
	outw( BASE + DATA_REG_W, 0x0608 );      /* frame type */
	outw( BASE + DATA_REG_W, 0x0100 );      /* H/W type */
	outw( BASE + DATA_REG_W, 0x0008 );      /* proto type */
	outw( BASE + DATA_REG_W, 0x0406 );      /* addr size */
	outw( BASE + DATA_REG_W, 0x0100 );      /* operation */
	outw( BASE + DATA_REG_W, 0x0000 );      /* src MAC addr */
	outw( BASE + DATA_REG_W, 0x6BE1 );
	outw( BASE + DATA_REG_W, 0xDE39 );
	outw( BASE + DATA_REG_W, 0x4A0A );      /* src IP addr */
	outw( BASE + DATA_REG_W, 0x6401 );      /* 10.74.1.100 */
	outw( BASE + DATA_REG_W, 0x0000 );      /* dst MAC addr */
	outw( BASE + DATA_REG_W, 0x0000 );
	outw( BASE + DATA_REG_W, 0x0000 );
	outw( BASE + DATA_REG_W, 0x4A0A );      /* dst IP addr */
	outw( BASE + DATA_REG_W, 0x2501 );      /* 10.74.1.37 */
	outw( BASE + DATA_REG_W, 0x6820 );	/* others */
	outw( BASE + DATA_REG_W, 0x6E61 );
	outw( BASE + DATA_REG_W, 0x6C64 );
	outw( BASE + DATA_REG_W, 0x6465 );
	outw( BASE + DATA_REG_W, 0x6300 );
	outw( BASE + DATA_REG_W, 0x656B );
	outw( BASE + DATA_REG_W, 0x2074 );
	outw( BASE + DATA_REG_W, 0x666F );
	outw( BASE + DATA_REG_W, 0x6C20 );
	outw( BASE + DATA_REG_W, 0x0000 );
#else /* CHECK_PRO */
	/* Push out the data to the card.
	 */
	for (top = m; m != 0; m = m->m_next) {
	    if ( (int)mtod(m, caddr_t) & 1) {
	        /* Odd begin address 
	         */
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	        ptr_reg = inw (BASE + POINTER_REG_W);

	        /* cannot access with byte length */
	        tmp_reg = (unsigned short)*(mtod(m, caddr_t)) & 0x00FF;
	        outw(BASE + DATA_REG_W, tmp_reg);

	        /* roll back the pointer */
	        outw(BASE + POINTER_REG_W, ptr_reg + 1);
#else
	        outb(BASE + DATA_REG_B, *(mtod(m, caddr_t)));
#endif
#ifdef DEBUG
tm_putstring("snstart1.\n");
#endif

	        /* Push out words.
	         */
	        outsw(BASE + DATA_REG_W,
			(unsigned short *)(mtod(m, caddr_t)+1), (m->m_len-1)/ 2);

	        /* Push out remaining byte.
	         */
	        if ((m->m_len-1) & 1) {
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	            ptr_reg = inw (BASE + POINTER_REG_W);

	            /* cannot access with byte length */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -