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

📄 if_snnew.c

📁 T-kernel Tcp/ip Protocol Stack Sample
💻 C
📖 第 1 页 / 共 5 页
字号:
	 * I wonder...
	 */
	x = splimp();

	/* Clear the watchdog.
	 */
	ifp->if_timer = 0;

	SMC_SELECT_BANK(2);

	/* Obtain the current interrupt mask and clear the hardware
	 * mask while servicing interrupts.
	 */
#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);
	outw( BASE + INTR_MASK_REG_W, 0x0000 );
#else
	mask = inb( BASE + INTR_MASK_REG_B );
	outb( BASE + INTR_MASK_REG_B, 0x00 );
#endif

	/* Get the set of interrupts which occurred and eliminate any
	 * which are masked.
	 */
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	/* cannot access with byte length */
	tmp_reg = inw( BASE + INTR_STAT_REG_W );
	interrupts = (u_char)(tmp_reg & 0x00FF);
#else
	interrupts = inb( BASE + INTR_STAT_REG_B );
#endif
	status = interrupts & mask;

	/* Now, process each of the interrupt types.
	 */

	/* Receive Overrun.
	 */
	if (status & IM_RX_OVRN_INT) {

	   /* Acknowlege Interrupt
	    */
	   SMC_SELECT_BANK(2);
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	   /* cannot access with byte length */
	   tmp_reg = (u_short)IM_RX_OVRN_INT & 0x00FF;
	   outw( BASE + INTR_ACK_REG_W, tmp_reg );
#else
	   outb(BASE + INTR_ACK_REG_B, IM_RX_OVRN_INT);
#endif

	   ++sc->arpcom.ac_if.if_ierrors;
	}

	/* Got a packet.
	 */
	if (status & IM_RCV_INT) {
	    snread(sc);
	}

	/* An on-card memory allocation came through.
	 */
	if (status & IM_ALLOC_INT) {
	    /* Disable this interrupt.
	     */
	    mask &= ~IM_ALLOC_INT;
	    sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
	    snresume(&sc->arpcom.ac_if);
	}


	/* TX Completion.  Handle a transmit error message.
	 * This will only be called when there is an error,
	 * because of the AUTO_RELEASE mode.
	 */
	if (status & IM_TX_INT) {

	    /* Acknowlege Interrupt
	     */
	    SMC_SELECT_BANK(2);
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	    /* cannot access with byte length */
	    tmp_reg = (u_short)IM_TX_INT & 0x00FF;
	    outw( BASE + INTR_ACK_REG_W, tmp_reg );
#else
	    outb(BASE + INTR_ACK_REG_B, IM_TX_INT);
#endif

	    packet_no = inw( BASE + FIFO_PORTS_REG_W );
	    packet_no &= FIFO_TX_MASK;

	    /* select this as the packet to read from
	     */
#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

	    /* Position the pointer to the first word from this packet
	     */
	    outw( BASE + POINTER_REG_W, PTR_AUTOINC | PTR_READ | 0x0000 );

		/* delay time to read the data reg. after setting the pointer reg. */
		inw( BASE + POINTER_REG_W );
		inw( BASE + POINTER_REG_W );

	    /* Fetch the TX status word.  The value found here will be
	     * a copy of the EPH_STATUS_REG_W at the time the transmit
	     * failed.
	     */
	    tx_status = inw( BASE + DATA_REG_W );

	    if ( tx_status & EPHSR_TX_SUC ) {
#ifdef PRINTON
	        printf("sn%d: Successful packet caused interrupt\n", ifp->if_unit);
#endif
	    } else {
	        ++sc->arpcom.ac_if.if_oerrors;
	    }

	    if ( tx_status & EPHSR_LATCOL )
	        ++sc->arpcom.ac_if.if_collisions;

	    /* Some of these errors will have disabled transmit.
	     * Re-enable transmit now.
	     */
	    SMC_SELECT_BANK( 0 );

	    flags = TCR_ENABLE;
#if !defined(SW_PAD)
	    flags |= TCR_PAD_ENABLE;
#endif

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

	    /* kill the failed packet.
	     * Wait for the MMU to be un-busy.
	     */
	    SMC_SELECT_BANK( 2 );
	    outw( BASE + MMU_CMD_REG_W, MMUCR_FREEPKT );
	    while ( inw( BASE + MMU_CMD_REG_W ) & MMUCR_BUSY ) /*NOTHING*/ ;

	    /*
	     * If there is no memory allocation oustanding, then
	     * attempt to queue more transmits.
	     */
	    if (sc->pages_wanted == -1) {
	        sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
	        snstart(&sc->arpcom.ac_if);
	    }
	}

	/* Transmit underrun.  We use this opportunity to
	 * update transmit statistics from the card.
	 */
	if (status & IM_TX_EMPTY_INT) {

	    /* Acknowlege Interrupt
	     */
	    SMC_SELECT_BANK( 2 );
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	    /* cannot access with byte length */
	    tmp_reg = (u_short)IM_TX_EMPTY_INT & 0x00FF;
	    outw( BASE + INTR_ACK_REG_W, tmp_reg );
#else
	    outb(BASE + INTR_ACK_REG_B, IM_TX_EMPTY_INT);
#endif

	    /* Disable this interrupt.
	     */
	    mask &= ~IM_TX_EMPTY_INT;

	    SMC_SELECT_BANK( 0 );
	    card_stats = inw( BASE + COUNTER_REG_W );

	    /* Single collisions
	     */
	    sc->arpcom.ac_if.if_collisions += card_stats & ECR_COLN_MASK;

	    /* Multiple collisions
	     */
	    sc->arpcom.ac_if.if_collisions += (card_stats & ECR_MCOLN_MASK) >> 4;

	    SMC_SELECT_BANK( 2 );

	    /*
	     * If there is no memory allocation oustanding, then
	     * attempt to enqueue some more stuff.
	     */
	    if (sc->pages_wanted == -1) {
	        sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
	        snstart(&sc->arpcom.ac_if);
	    }
	}

	/* Some other error.  Try to fix it by resetting the adapter.
	 */
	if (status & IM_EPH_INT) {
	    snstop();
	    sninit(0);
	}



#if defined(LAN91C111)
	/* PHY MI state has changed */
	if (status & IM_MDINT) {
	    /* Acknowlege Interrupt */
	    SMC_SELECT_BANK( 2 );
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	    /* cannot access with byte length */
	    tmp_reg = (u_short)IM_MDINT & 0x00FF;
	    outw( BASE + INTR_ACK_REG_W, tmp_reg );
#else
	    outb(BASE + INTR_ACK_REG_B, IM_MDINT);
#endif

	    phy_ints();
	}
#endif

	/* Handled all interrupt sources.
	 */

	SMC_SELECT_BANK( 2 );

	/* Reestablish interrupts from mask which have not been deselected
	 * during this interrupt.  Note that the hardware mask, which was set
	 * to 0x00 at the start of this service routine, may have been updated
	 * by one or more of the interrupt handers and we must let those
	 * new interrupts stay enabled here.
	 */
#if defined(_STD_SH727_) || defined(_MIC_SH7145_)
	/* cannot access with byte length */
	tmp_reg = inw( BASE + INTR_MASK_REG_W );
	mask |= (u_char)(tmp_reg >> 8);
	tmp_reg = (u_short)(mask << 8);
	outw( BASE + INTR_MASK_REG_W, tmp_reg );
#else
	mask |= inb( BASE + INTR_MASK_REG_B );
	outb( BASE + INTR_MASK_REG_B, mask );
#endif
	sc->intr_mask = mask;

	splx(x);
}

void
snread(struct sn_softc *sc)
{
	struct ether_header *eh;
	struct mbuf *top, *mcur, *m;
	int lenthisone;

	short rx_fifo2, status;
	register short delta;
	register short rx_fifo;

	int packet_number;
	u_short packet_length;
	u_char *data;
	int i;
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	volatile unsigned short tmp_reg;
#endif

#if !defined(ORIGINAL)
	for (i=0; i < SN_MAX_RECV_COUNT; i++) {
#endif
	SMC_SELECT_BANK( 2 );
	packet_number = inw( BASE + FIFO_PORTS_REG_W );

	if ( packet_number & FIFO_REMPTY ) {

	    /* we got called , but nothing was on the FIFO
	     */
#ifdef PRINTON
	    printf("sn: Receive interrupt with nothing on FIFO\n");
#endif
	    return;
	}

read_another:
	/* Start reading from the start of the packet.
	 * Since PTR_RCV is set, packet number is found
	 * in FIFO_PORTS_REG_W, FIFO_RX_MASK.
	 */
	outw( BASE + POINTER_REG_W, PTR_READ | PTR_RCV | PTR_AUTOINC | 0x0000 );

#if !defined(OLD)
	/* delay time to read the data reg. after setting the pointer reg. */
	inw( BASE + POINTER_REG_W );
	inw( BASE + POINTER_REG_W );
#endif
	/* First two words are status and packet_length
	 */
	status = inw( BASE + DATA_REG_W );
	packet_length = inw( BASE + DATA_REG_W ) & RLEN_MASK;

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

	/*
	 * The packet length contains 3 extra words:
	 * status, length, and a extra word with the control byte.
	 */
	packet_length -= 6;

	/* Account for receive errors and discard.
	 */
	if (status & RS_ERRORS) {
	    ++sc->arpcom.ac_if.if_ierrors;
	    goto out;
	}

	/* A packet is received.
	 */

	/* Adjust for odd-length packet.
	 */
	if ( status & RS_ODDFRAME ) {
		packet_length++;
	}

	/* Allocate a header mbuf from the kernel.
	 */
	MGETHDR(m, M_DONTWAIT, MT_DATA);
	if (m == NULL) {
	    goto out;
	}

	m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
	m->m_pkthdr.len = m->m_len = packet_length;

	/* Attach an mbuf cluster
	 */
	MCLGET(m, M_DONTWAIT);

	/* Insist on getting a cluster
	 */
	if ((m->m_flags & M_EXT) == 0) {
	    m_freem(m);
	    ++sc->arpcom.ac_if.if_ierrors;
#ifdef PRINTON
	    printf("sn: snread() kernel memory allocation problem\n");
#endif
	    goto out;
	}

#if defined(_MIC_M32192_)||defined(_STD_SH7727_)||defined(_MIC_SH7145_)||(_MIC_M32104_)
	/* We change offset to set IP header's alignment to 4byte */
	m->m_data += 2;
#endif

	eh = mtod(m, struct ether_header *);

	/*
	 * Get packet, including link layer address, from interface.
	 */

	data = (u_char *) eh;
	insw(BASE + DATA_REG_W, (unsigned short *)data, packet_length >> 1);
	if ( packet_length & 1 ) {
	    data += packet_length & ~1;
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
	    /* cannot access with byte length */
	    tmp_reg = inw(BASE + DATA_REG_W);
	    *data = (unsigned char)(tmp_reg & 0x00FF);
#else
	    *data = inb( BASE + DATA_REG_B );
#endif
#ifdef DEBUG
tm_putstring("snread.\n");
#endif
	}

	++sc->arpcom.ac_if.if_ipackets;

	/*
	 * Remove link layer addresses and whatnot.
	 */
	m->m_pkthdr.len = m->m_len = packet_length - sizeof(struct ether_header);
	m->m_data += sizeof(struct ether_header);

	(void)ether_input(&sc->arpcom.ac_if, eh, m);

out:
	/* Error or good, tell the card to get rid of this packet
	 * Wait for the MMU to be un-busy.
	 */
	SMC_SELECT_BANK( 2 );
	outw( BASE + MMU_CMD_REG_W, MMUCR_RELEASE );
	while ( inw( BASE + MMU_CMD_REG_W ) & MMUCR_BUSY ) /*NOTHING*/ ;

#if defined(ORIGINAL)
	/* Check whether another packet is ready
	 */
	packet_number = inw( BASE + FIFO_PORTS_REG_W );
	if ( packet_number & FIFO_REMPTY ) {
	    return;
	}

	goto read_another;
#else
	} /* for */
#endif
}

/*
 * Handle IOCTLS.  This function is completely stolen from if_ep.c
 * As with its progenitor, it does not handle hardware address
 * changes.
 */
static int
snioctl(struct ifnet *ifp, unsigned int cmd, caddr_t data)
{
	register struct ifaddr *ifa = (struct ifaddr *) data;
	struct sn_softc *sc = &sn_softc0;
	struct ifreq *ifr = (struct ifreq *) data;
	int s, error = 0;

	s = splimp();

	switch (cmd) {
	  case SIOCSIFADDR:
	    ifp->if_flags |= IFF_UP;
	    switch (ifa->ifa_addr->sa_family) {
#ifdef INET
	      case AF_INET:
	        sninit(0);       /* before arpwhohas */
	        arp_ifinit((struct arpcom *)ifp, ifa);
	        break;
#endif
	      default:
	        sninit(0);
	        break;
	    }
	    break;
	  case SIOCGIFADDR:
	    {
	      struct sockaddr *sa;

	      sa = (struct sockaddr *) & ifr->ifr_data;
	      bcopy((caddr_t) sc->arpcom.ac_enaddr,
	            (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
	    }
	    break;
	  case SIOCSIFFLAGS:

⌨️ 快捷键说明

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