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

📄 3c509.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 3 页
字号:
 * DESCRIPTION: Completes the initialization/attachement of the driver. * * RETURNS: 0 - ok. * **********************************************************************************/static int ep_attach( struct ep_softc *sc ){    u_short *p;    int i;        /*     * Setup the station address     */    p = (u_short *) &sc->arpcom.ac_enaddr;    GO_WINDOW(2);    printf("ADDRESS=" );    for (i = 0; i < 3; i++)     {	    p[i] = htons( sc->epb->eth_addr[i] );        outw( BASE + EP_W2_ADDR_0 + (i * 2), ntohs( p[i] ) );        printf("%04x ", (u_short)ntohs( p[i] ) );    }    printf("\n" );        sc->rx_no_first = sc->rx_no_mbuf =	sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl =	sc->tx_underrun = 0;    ep_fset( F_RX_FIRST );    sc->top = sc->mcur = 0;    return 0;}/********************************************************************************** *  * DESCRIPTION: * Initializes the card. * The order in here seems important. Otherwise we may not receive interrupts. ?! * * RETURNS: nothing. * **********************************************************************************/static void epinit( struct ep_softc *sc ){    register struct ifnet *ifp = &sc->arpcom.ac_if;    int i, j;    while( inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS ) ;    GO_WINDOW(0);    outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);    GO_WINDOW(4);    outw(BASE + EP_W4_MEDIA_TYPE, DISABLE_UTP);    GO_WINDOW(0);    /* Disable the card */    outw(BASE + EP_W0_CONFIG_CTRL, 0);    /* Enable the card */    outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);    GO_WINDOW(2);    /* Reload the ether_addr. */    for (i = 0; i < 6; i++)       outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]);    outw(BASE + EP_COMMAND, RX_RESET);    outw(BASE + EP_COMMAND, TX_RESET);    while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);    /* Window 1 is operating window */    GO_WINDOW(1);    for (i = 0; i < 31; i++)       inb(BASE + EP_W1_TX_STATUS);    /* get rid of stray intr's */    outw(BASE + EP_COMMAND, ACK_INTR | 0xff);    outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_5_INTS);    outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS);    if (ifp->if_flags & IFF_PROMISC)	   outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |	 						    FIL_GROUP | FIL_BRDCST | FIL_ALL);    else	   outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | FIL_GROUP | FIL_BRDCST);     /*      * S.B.      *      * Now behavior was slightly changed:      *      * if any of flags link[0-2] is used and its connector is      * physically present the following connectors are used:      *      *   link0 - AUI * highest precedence      *   link1 - BNC      *   link2 - UTP * lowest precedence      *      * If none of them is specified then      * connector specified in the EEPROM is used      * (if present on card or AUI if not).      *      */    /* Set the xcvr. */    if (ifp->if_flags & IFF_LINK0 && sc->ep_connectors & AUI)     {	   i = ACF_CONNECTOR_AUI;    }     else if (ifp->if_flags & IFF_LINK1 && sc->ep_connectors & BNC)     {	   i = ACF_CONNECTOR_BNC;    }     else if (ifp->if_flags & IFF_LINK2 && sc->ep_connectors & UTP)     {	   i = ACF_CONNECTOR_UTP;    }     else     {	   i = sc->ep_connector;    }    GO_WINDOW(0);    j = inw(BASE + EP_W0_ADDRESS_CFG) & 0x3fff;    outw(BASE + EP_W0_ADDRESS_CFG, j | (i << ACF_CONNECTOR_BITS));    switch(i)     {      case ACF_CONNECTOR_UTP:	  if (sc->ep_connectors & UTP) 	  {	    GO_WINDOW(4);	    outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP);	  }	  break;      case ACF_CONNECTOR_BNC:	   if (sc->ep_connectors & BNC) 	   {	    outw(BASE + EP_COMMAND, START_TRANSCEIVER);	    Wait_X_ms( 1 );	   }       break;      case ACF_CONNECTOR_AUI:  	    /* nothing to do */		break;      default:	   printf("ep%d: strange connector type in EEPROM: assuming AUI\n", sc->unit);	   break;    }    outw(BASE + EP_COMMAND, RX_ENABLE);    outw(BASE + EP_COMMAND, TX_ENABLE);    ifp->if_flags |= IFF_RUNNING;    ifp->if_flags &= ~IFF_OACTIVE;	/* just in case */    sc->rx_no_first = sc->rx_no_mbuf =	sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl =	sc->tx_underrun = 0;    ep_fset(F_RX_FIRST);    if( sc->top )     {	   m_freem( sc->top );	   sc->top = sc->mcur = 0;    }    outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);    outw(BASE + EP_COMMAND, SET_TX_START_THRESH | 16);    /*     * Store up a bunch of mbuf's for use later. (MAX_MBS). First we free up     * any that we had in case we're being called from intr or somewhere     * else.     */    GO_WINDOW(1);}static const char padmap[] = {0, 3, 2, 1};/********************************************************************************** *  * DESCRIPTION: Routine to transmit frames to the card. * * RETURNS: nothing. * **********************************************************************************/static void epstart( struct ifnet *ifp ){    register struct ep_softc *sc = ifp->if_softc;    register u_int len;    register struct mbuf *m;    struct mbuf *top;    int pad;    while( inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS )         ;startagain:    /*    printk( "S-" ); */    /* Sneak a peek at the next packet */    m = ifp->if_snd.ifq_head;    if (m == 0)     {       ifp->if_flags &= ~IFF_OACTIVE;       return;    }    for( len = 0, top = m; m; m = m->m_next )         len += m->m_len;    pad = padmap[ len & 3 ];    /*     * The 3c509 automatically pads short packets to minimum ethernet length,     * but we drop packets that are too large. Perhaps we should truncate     * them instead?     */    if( len + pad > ETHER_MAX_LEN )     {	   /* packet is obviously too large: toss it */       ++ifp->if_oerrors;       IF_DEQUEUE( &ifp->if_snd, m );       m_freem( m );   	   goto readcheck;    }    if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4)     {	   /* no room in FIFO */	   outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4));       /* make sure */	   if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) 	   {	       ifp->if_flags |= IFF_OACTIVE;	       return;	   }    }    IF_DEQUEUE( &ifp->if_snd, m );    outw(BASE + EP_W1_TX_PIO_WR_1, len);     outw(BASE + EP_W1_TX_PIO_WR_1, 0x0);	/* Second dword meaningless */    for (top = m; m != 0; m = m->m_next)	{       if( ep_ftst(F_ACCESS_32_BITS ) )        {	      outsl( BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 4 );	      if( m->m_len & 3 )             outsb(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t) + (m->m_len & (~3)), m->m_len & 3 );       }        else        {	      outsw( BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 2 );	      if( m->m_len & 1 )		  outb( BASE + EP_W1_TX_PIO_WR_1, *(mtod(m, caddr_t) + m->m_len - 1) );	   }	}    while( pad-- )	{  	   outb(BASE + EP_W1_TX_PIO_WR_1, 0);	/* Padding */	}    ifp->if_timer = 2;    ifp->if_opackets++;    m_freem(top);/*    goto startagain;   */    /*     * Is another packet coming in? We don't want to overflow the tiny RX     * fifo.     */readcheck:    if( inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK )     {	/*	 * we check if we have packets left, in that case we prepare to come	 * back later	 */	   if( ifp->if_snd.ifq_head ) 	   {	      outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8);       }	   return;    }    goto startagain;}/********************************************************************************** *  * DESCRIPTION: Routine to read frames from the card. * * RETURNS: nothing. * **********************************************************************************/static void epread( register struct ep_softc *sc ){    struct ether_header *eh;    struct mbuf *top, *mcur, *m;    struct ifnet *ifp;    int lenthisone;    short rx_fifo2, status;    register short rx_fifo;    ifp = &sc->arpcom.ac_if;    status = inw( BASE + EP_W1_RX_STATUS );read_again:    if (status & ERR_RX)     {	   ++ifp->if_ierrors;	   if( status & ERR_RX_OVERRUN ) 	   {	    /*	     * we can think the rx latency is actually greather than we	     * expect	     */	    if( ep_ftst(F_RX_FIRST) ) 		   sc->rx_overrunf++;	    else		   sc->rx_overrunl++;	   }	   goto out;    }    rx_fifo = rx_fifo2 = status & RX_BYTES_MASK;    if( ep_ftst( F_RX_FIRST ) )     {	   MGETHDR( m, M_DONTWAIT, MT_DATA );       if( !m )	      goto out;	   if( rx_fifo >= MINCLSIZE )	      MCLGET( m, M_DONTWAIT );	   sc->top = sc->mcur = top = m;#define EROUND  ((sizeof(struct ether_header) + 3) & ~3)#define EOFF    (EROUND - sizeof(struct ether_header))	   top->m_data += EOFF;  	   /* Read what should be the header. */	   insw(BASE + EP_W1_RX_PIO_RD_1, mtod(top, caddr_t), sizeof(struct ether_header) / 2);	   top->m_len = sizeof(struct ether_header);	   rx_fifo -= sizeof(struct ether_header);	   sc->cur_len = rx_fifo2;    }     else     {	   /* come here if we didn't have a complete packet last time */	   top = sc->top;	   m = sc->mcur;	   sc->cur_len += rx_fifo2;    }    /* Reads what is left in the RX FIFO */    while (rx_fifo > 0)     {	   lenthisone = min( rx_fifo, M_TRAILINGSPACE(m) );	   if( lenthisone == 0 ) 	   {	/* no room in this one */	       mcur = m;	       MGET(m, M_WAIT, MT_DATA);	       if (!m)		      goto out;	       if (rx_fifo >= MINCLSIZE)		       MCLGET(m, M_WAIT);	       m->m_len = 0;	       mcur->m_next = m;	       lenthisone = min(rx_fifo, M_TRAILINGSPACE(m));	   }	   if( ep_ftst( F_ACCESS_32_BITS ) ) 	   { /* default for EISA configured cards*/	      insl( BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, lenthisone / 4);	      m->m_len += (lenthisone & ~3);	      if (lenthisone & 3)		     insb(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, lenthisone & 3);	      m->m_len += (lenthisone & 3);	    } 	    else 	    {	      insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, lenthisone / 2);	      m->m_len += lenthisone;	      if( lenthisone & 1 )		     *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);	   }	   rx_fifo -= lenthisone;    }    if( status & ERR_RX_INCOMPLETE)     {	/* we haven't received the complete packet */	    sc->mcur = m;     	sc->rx_no_first++;	/* to know how often we come here */     	ep_frst( F_RX_FIRST );	    if( !((status = inw(BASE + EP_W1_RX_STATUS)) & ERR_RX_INCOMPLETE) ) 	    {	      /* we see if by now, the packet has completly arrived */	      goto read_again;	    }	    outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_NEXT_EARLY_THRESH);	    return;    }    outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);    ++ifp->if_ipackets;    ep_fset(F_RX_FIRST);    top->m_pkthdr.rcvif = &sc->arpcom.ac_if;    top->m_pkthdr.len = sc->cur_len;    eh = mtod(top, struct ether_header *);    m_adj(top, sizeof(struct ether_header));    ether_input(ifp, eh, top);    sc->top = 0;    while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)          ;    outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);    return;out:    outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);    if (sc->top)     {	   m_freem(sc->top);	   sc->top = 0;       sc->rx_no_mbuf++;    }    ep_fset(F_RX_FIRST);    while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) ;    outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);}/********************************************************************************** *  * DESCRIPTION:  * This routine handles interrupts. It is called from the "RX" task whenever  * the ISR post an event to the task.  * This is basically the "isr" from the FreeBSD driver. * * RETURNS: nothing. * **********************************************************************************/static void ep_intr( struct ep_softc *sc ){  register int status;  struct ifnet *ifp;  ifp = &sc->arpcom.ac_if;rescan:  /*  printk( "I-" ); */  while( ( status = inw(BASE + EP_STATUS)) & S_5_INTS )   {	/* first acknowledge all interrupt sources */    outw( BASE + EP_COMMAND, ACK_INTR | ( status & S_MASK ) );	if( status & ( S_RX_COMPLETE | S_RX_EARLY ) ) 	{	    epread( sc );	    continue;	}	if (status & S_TX_AVAIL) 	{	    /* we need ACK */	    ifp->if_timer = 0;	    ifp->if_flags &= ~IFF_OACTIVE;	    GO_WINDOW(1);	    inw(BASE + EP_W1_FREE_TX);	    epstart(ifp);	}	if (status & S_CARD_FAILURE) 	{	    ifp->if_timer = 0;	    printf("\nep%d:\n\tStatus: %x\n", sc->unit, status);	    GO_WINDOW(4);	    printf("\tFIFO Diagnostic: %x\n", inw(BASE + EP_W4_FIFO_DIAG));	    printf("\tStat: %x\n", sc->stat);	    printf("\tIpackets=%ld, Opackets=%ld\n", ifp->if_ipackets, ifp->if_opackets);	    printf("\tNOF=%d, NOMB=%d, BPFD=%d, RXOF=%d, RXOL=%d, TXU=%d\n",		   sc->rx_no_first, sc->rx_no_mbuf, sc->rx_bpf_disc, sc->rx_overrunf,		   sc->rx_overrunl, sc->tx_underrun);	    printf("ep%d: Status: %x (input buffer overflow)\n", sc->unit, status);	    ++ifp->if_ierrors;	    epinit(sc);	    return;	}	if (status & S_TX_COMPLETE) 	{	    ifp->if_timer = 0;	    /* we  need ACK. we do it at the end */	    /*	     * We need to read TX_STATUS until we get a 0 status in order to	     * turn off the interrupt flag.	     */	    while ((status = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) 	    {		   if (status & TXS_SUCCES_INTR_REQ)		        ;		   else if( status & (TXS_UNDERRUN | TXS_JABBER | TXS_MAX_COLLISION ) ) 		   {		      outw(BASE + EP_COMMAND, TX_RESET);		      if (status & TXS_UNDERRUN) 		      {			     sc->tx_underrun++;		      } 		      else 		      {			      if( status & TXS_JABBER )			           ;		          else	/* TXS_MAX_COLLISION - we shouldn't get here */			           ++ifp->if_collisions;		      }		      ++ifp->if_oerrors;		      outw(BASE + EP_COMMAND, TX_ENABLE);		     /*		      * To have a tx_avail_int but giving the chance to the		      * Reception		      */		      if( ifp->if_snd.ifq_head ) 		      {			     outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8);		      }		   }		   outb( BASE + EP_W1_TX_STATUS, 0x0 );	/* pops up the next status */	    } /* while */	    ifp->if_flags &= ~IFF_OACTIVE;	    GO_WINDOW(1);	    inw(BASE + EP_W1_FREE_TX);	    epstart( ifp );	}  /* end TX_COMPLETE */  }  outw(BASE + EP_COMMAND, C_INTR_LATCH);	/* ACK int Latch */  if( (status = inw(BASE + EP_STATUS) ) & S_5_INTS )      goto rescan;     /* re-enable Ints */  outw( BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS );  /* printk( "I+" ); */}

⌨️ 快捷键说明

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