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

📄 smc9218.c

📁 一个DSP_TCPIP 协议栈网络驱动的例子
💻 C
📖 第 1 页 / 共 2 页
字号:
    if ( lp->mii.force_media ) {
        smc911x_phy_fixed( ei_local );
        goto smc911x_phy_configure_exit;
    }

    /* Copy our capabilities from MII_BMSR to MII_ADVERTISE */
    SMC_GET_PHY_BMSR( phyaddr, my_phy_caps );
    if (!( my_phy_caps & BMSR_ANEGCAPABLE )) {
        smc911x_phy_fixed( ei_local );
        goto smc911x_phy_configure_exit;
    }

    /* CSMA capable w/ both pauses */
    my_ad_caps = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;

    if ( my_phy_caps & BMSR_100BASE4 )
        my_ad_caps |= ADVERTISE_100BASE4;
    if ( my_phy_caps & BMSR_100FULL )
        my_ad_caps |= ADVERTISE_100FULL;
    if ( my_phy_caps & BMSR_100HALF )
        my_ad_caps |= ADVERTISE_100HALF;
    if ( my_phy_caps & BMSR_10FULL )
        my_ad_caps |= ADVERTISE_10FULL;
    if ( my_phy_caps & BMSR_10HALF )
        my_ad_caps |= ADVERTISE_10HALF;

    /* Disable capabilities not selected by our user */
    if ( lp->ctl_rspeed != 100 )
        my_ad_caps &= ~( ADVERTISE_100BASE4 | ADVERTISE_100FULL | ADVERTISE_100HALF );

    if (! lp->ctl_rfduplx )
        my_ad_caps &= ~( ADVERTISE_100FULL | ADVERTISE_10FULL );

    /* Update our Auto-Neg Advertisement Register */
    SMC_SET_PHY_MII_ADV( phyaddr, my_ad_caps );
    lp->mii.advertising = my_ad_caps;

    /*
     * Read the register back.   Without this, it appears that when
     * auto-negotiation is restarted, sometimes it isn't ready and
     * the link does not come up.
     */
    udelay( 10 );
    SMC_GET_PHY_MII_ADV( phyaddr, status );

    /* Restart auto-negotiation process in order to advertise my caps */
    SMC_SET_PHY_BMCR( phyaddr, BMCR_ANENABLE | BMCR_ANRESTART );

    smc911x_phy_check_media( ei_local, 1 );

smc911x_phy_configure_exit:
smc911x_phy_configure_exit_nolock:
    lp->work_pending = 0;
}

/*
 * Enable Interrupts, Receive, and Transmit
 */
static void smc911x_enable( struct ei_device* ei_local )
{
    unsigned int ioaddr = ei_local->base;
    unsigned int mask, cfg, cr;

    /* 装入MAC地址 */
    SMC_SET_MAC_ADDR( ei_local->paddr);

    /* Enable TX */
    cfg = SMC_GET_HW_CFG();
    cfg &= HW_CFG_TX_FIF_SZ_ | 0xFFF; /* 配置 */
    cfg |= HW_CFG_SF_;
    SMC_SET_HW_CFG( cfg );
    SMC_SET_FIFO_TDA( 0xFF ); /* FIFO中断配置 */
    SMC_SET_FIFO_TSL( 64 );  /* Update TX stats on every 64 packets received or every 1 sec */
    //SMC_SET_GPT_CFG( GPT_CFG_TIMER_EN_ | 10000 ); /* 定时器设置 */

    SMC_GET_MAC_CR( cr );
    cr &= ~ MAC_CR_PRMS_;
    cr |= MAC_CR_TXEN_ | MAC_CR_FDPX_ /*| MAC_CR_HBDIS_ */;
    SMC_SET_MAC_CR( cr );
    SMC_SET_TX_CFG( TX_CFG_TX_ON_ );
    /* Add 2 byte padding to start of packets */
    SMC_SET_RX_CFG( RX_CFG_RX_END_ALGN4_ | (( 2 << 8 ) & RX_CFG_RXDOFF_ ));
    //SMC_SET_TX_CFG((2<<8) & RX_CFG_RXDOFF_);
    /* Turn on receiver and enable RX */
    cr = cr | MAC_CR_RXEN_ ;
    SMC_SET_MAC_CR( cr );
    /* Interrupt on every received packet */
    SMC_SET_FIFO_RSA( 0x01 ); /* RSA */
    SMC_SET_FIFO_RSL( 0x00 ); /* RSL */
#if 0
    /* now, enable interrupts */
    mask = INT_EN_RSFL_EN_ | INT_EN_RXE_EN_ ;
    //   mask = INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_ | INT_EN_RSFL_EN_ |
    //       INT_EN_GPT_INT_EN_ | INT_EN_RXDFH_INT_EN_ | INT_EN_RXE_EN_ |
    //       INT_EN_PHY_INT_EN_;
    if ( IS_REV_A( lp->revision ))
        mask |= INT_EN_RDFL_EN_;
    else {
        mask |= INT_EN_RXDF_EN_;
    }
#endif
    mask = 0x6008; /* 中断掩码 */
    /* 使能LED */
    SMC_SET_GPIO_CFG( 7 << 28 );
    SMC_ENABLE_INT( mask );
}

/*******************************************************************************
**初始化网络控制芯片控制结构接口
*******************************************************************************/
static void smc9218_init_prep( struct ei_device * ei_local )
{
    unsigned int ioaddr; /* IO基地址 */
    struct smc911x_local * lp; /* 私有控制结构 */
    ioaddr = ei_local->base; /* 获取基地址 */
    lp = ( struct smc911x_local *)malloc( sizeof( struct smc911x_local ));
    memset( lp, 0, sizeof( struct smc911x_local )); /* 初始化 */
    ei_local->data = (void*)lp;
    lp->netdev = ei_local;

    lp->version = SMC_GET_PN();
    lp->revision = SMC_GET_REV();
    lp->tx_fifo_kb = tx_fifo_kb;
    /* Reverse calculate the RX FIFO size from the TX */
    lp->tx_fifo_size = ( lp->tx_fifo_kb << 10 ) - 512; /* 缺省设置 */
    lp->rx_fifo_size = (( 0x4000 - 512 - lp->tx_fifo_size ) / 16 ) * 15; /* 缺省设置 */
    /* Set the automatic flow control values */
    switch( lp->tx_fifo_kb ) {
        /*
         *   AFC_HI is about ((Rx Data Fifo Size)*2/3)/64
         *   AFC_LO is AFC_HI/2
         *   BACK_DUR is about 5uS*(AFC_LO) rounded down
         */
    case 2:/* 13440 Rx Data Fifo Size */
        lp->afc_cfg = 0x008C46AF; break; /* 13440 Rx Data Fifo Size */
    case 3:/* 12480 Rx Data Fifo Size */
        lp->afc_cfg = 0x0082419F; break; /* 12480 Rx Data Fifo Size */
    case 4:/* 11520 Rx Data Fifo Size */
        lp->afc_cfg = 0x00783C9F; break; /* 11520 Rx Data Fifo Size */
    case 5:/* 10560 Rx Data Fifo Size */
        lp->afc_cfg = 0x006E374F; break; /* 10560 Rx Data Fifo Size */
    case 6:/* 9600 Rx Data Fifo Size */
        lp->afc_cfg = 0x0064328F; break; /* 9600 Rx Data Fifo Size */
    case 7:/* 8640 Rx Data Fifo Size */
        lp->afc_cfg = 0x005A2D7F; break; /* 8640 Rx Data Fifo Size */
    case 8:/* 7680 Rx Data Fifo Size */
        lp->afc_cfg = 0x0050287F; break; /* 7680 Rx Data Fifo Size */
    case 9:/* 6720 Rx Data Fifo Size */
        lp->afc_cfg = 0x0046236F; break; /* 6720 Rx Data Fifo Size */
    case 10:/* 5760 Rx Data Fifo Size */
        lp->afc_cfg = 0x003C1E6F; break; /* 5760 Rx Data Fifo Size */
    case 11:/* 4800 Rx Data Fifo Size */
        lp->afc_cfg = 0x0032195F; break; /* 4800 Rx Data Fifo Size */
        /*
         *   AFC_HI is ~1520 bytes less than RX Data Fifo Size
         *   AFC_LO is AFC_HI/2
         *   BACK_DUR is about 5uS*(AFC_LO) rounded down
         */
    case 12:/* 3840 Rx Data Fifo Size */
        lp->afc_cfg = 0x0024124F; break; /* 3840 Rx Data Fifo Size */
    case 13:/* 2880 Rx Data Fifo Size */
        lp->afc_cfg = 0x0015073F; break; /* 2880 Rx Data Fifo Size */
    case 14:/* 1920 Rx Data Fifo Size */
        lp->afc_cfg = 0x0006032F; break; /* 1920 Rx Data Fifo Size */
    default:
        break;
    }

    /* MII初始化 */
    lp->mii.phy_id_mask = 0x1f; /* 缺省设置 */
    lp->mii.reg_num_mask = 0x1f; /* 缺省设置 */
    lp->mii.force_media = 0; /* 缺省设置 */
    lp->mii.full_duplex = 1; /* 缺省设置 */
    lp->mii.dev = lp->netdev;
    lp->mii.mdio_read = smc911x_phy_read;
    lp->mii.mdio_write = smc911x_phy_write;

    //smc911x_reset( iface );
    /*
     * Locate the phy, if any.
     */
    smc911x_phy_detect( ei_local );

    lp->msg_enable = 1; /* MSG_ENABLE */
    lp->ctl_rfduplx = 1; /* 缺省设置 */
    lp->ctl_rspeed = 100; /* 缺省设置 */
}

/* 初始化芯片,然后启动运行 */
static int smc9218_init( struct ei_device * ei_local )
{
    /* Configure the PHY, initialize the link state */
    smc911x_phy_configure( ei_local );

    /* Turn on Tx + Rx */
    smc911x_enable( ei_local );
    return 0;
}

/* 发送处理函数
   iface : 网络接口
   buffer: 待发送的数据
   len: 待发送的数据长度
*/
static void smc9218_send_packet( struct ei_device * ei_local, char * buffer, unsigned int length )
{
    unsigned int ioaddr = ei_local->base;
    struct smc911x_local * lp = ( struct smc911x_local *)ei_local->data;
    unsigned int cmdA, cmdB, len;

    unsigned int free;
    unsigned status;
    unsigned char * buf;

    IRQ_disable( 6 ); /* 关闭中断 */

    while((( SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TSUSED_ ) >> 16 ) != 0 ) /* TX FIFO */
    {
        status = SMC_GET_TX_STS_FIFO();
        lp->stat.tx_packets ++;
        lp->stat.tx_bytes += ( status >> 16 ); /* 发送数据长度 */
    }

    free = SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TDFREE_;
    /* Turn off the flow when running out of space in FIFO */
#if 0
    if ( free <= SMC911X_TX_FIFO_LOW_THRESHOLD ) {
        /* Reenable when at least 1 packet of size MTU present */
        SMC_SET_FIFO_TDA(( SMC911X_TX_FIFO_LOW_THRESHOLD )/ 64 ); /* 重新设置可用发送区 */
        lp->tx_throttle = 1;
    }
#endif
    /* Drop packets when we run out of space in TX FIFO
     * Account for overhead required for:
     *
     *    Tx command words           8 bytes
     *    Start offset               15 bytes
     *    End padding                15 bytes
     */
    if ( free < ( length + 8 + 15 + 15 )) { /* 比较空闲位置 */
        lp->stat.tx_errors ++;
        lp->stat.tx_dropped ++;
        IRQ_enable( 6 ); /* 开启中断 */
        return ;
    }
    /* 计数缓存地址 */
    buf = ( unsigned char *)(( unsigned int )( buffer + 2 ) & ~ 0x3 );
    /* 计数发送长度 */
    len = ( length + 3 + (( unsigned int )( buffer + 2 ) & 3 )) & ~ 0x3;
    /* 填写命令A */
    cmdA = ((( unsigned int )( buffer + 2 ) & 0x3 ) << 16 ) | TX_CMD_A_INT_FIRST_SEG_
        | TX_CMD_A_INT_LAST_SEG_ | length ;

    /* tag is packet length so we can use this in stats update later */
    cmdB = ( length  << 16 ) | ( length & 0x7FF ); /* COMMAND B 构造 */
    SMC_SET_TX_FIFO( cmdA );
    SMC_SET_TX_FIFO( cmdB );
    SMC_PUSH_DATA(( unsigned int *)buf, len );
    IRQ_enable( 6 );/* 开启中断 */
}

static void smc911x_drop_pkt( struct ei_device* ei_local )
{
    unsigned int ioaddr = ei_local->base;
    unsigned int fifo_count, timeout, reg;

    fifo_count = SMC_GET_RX_FIFO_INF() & 0xFFFF; /* 当前接收FIFO数目 */
    if ( fifo_count <= 4 ) { /* 如果数目小于4 */
        /* Manually dump the packet data */
        while ( fifo_count --)
            SMC_GET_RX_FIFO();
    } else   {
        /* Fast forward through the bad packet */
        SMC_SET_RX_DP_CTRL( RX_DP_CTRL_FFWD_BUSY_ );
        timeout = 50; /* 超时设置 */
        do {
            // udelay( 10 ); /* 延时 */
            reg = SMC_GET_RX_DP_CTRL() & RX_DP_CTRL_FFWD_BUSY_;
        } while ( timeout -- && reg );
    }
}

extern far SWI_Obj NET_swi;
extern far SWI_Handle NET_swi_handle = & NET_swi;

/* 接收数据 */
static void smc9218_rcv( struct ei_device * ei_local )
{
    unsigned int ioaddr = ei_local->base;
    struct smc911x_local * lp = ( struct smc911x_local *)ei_local->data;
    unsigned int pkt_len, status;
    void * skb; /* 网络缓冲区结构指针 */
    unsigned char * data;
    char times = 10; /* 循环10次 */
    int recved = 0;

    /* 查询接收FIFO */
    status = SMC_GET_RX_FIFO_INF() >> 16;
    /* 没有数据 */
    while( status  != 0 && times -- )
    {
        status = SMC_GET_RX_STS_FIFO();
        pkt_len = ( status & RX_STS_PKT_LEN_ ) >> 16; /* 报文长度 */

        if ( status & RX_STS_ES_ ) {
            /* Deal with a bad packet */
            lp->stat.rx_errors ++;
            if ( status & RX_STS_CRC_ERR_ )
                lp->stat.rx_crc_errors ++;
            else {
                if ( status & RX_STS_LEN_ERR_ )
                    lp->stat.rx_length_errors ++;
                if ( status & RX_STS_MCAST_ )
                    lp->stat.multicast ++;
            }
            /* Remove the bad packet data from the RX FIFO */
            smc911x_drop_pkt( ei_local );
        }
        else {
            /* Receive a valid packet */
            /* Alloc a buffer with extra room for DMA alignment */
            skb = get_skb( pkt_len, ( char **)& data );
            if ( skb == NULL )
            {
                lp->stat.rx_dropped ++;
                smc911x_drop_pkt( ei_local );
                break;
            }
            SMC_SET_RX_CFG( RX_CFG_RX_END_ALGN4_ | (( 2 << 8 ) & RX_CFG_RXDOFF_ )); /* RX 配置*/
            //FCT_WordToByte(( void *)data, ( void *)ioaddr, ( int )(( pkt_len + 3 )>> 2 ));/* 接收数据 */
            SMC_PULL_DATA( ( unsigned int *)data, pkt_len + 2 + 3 ); /* 接收数据 */
            set_skb( ei_local->iface, skb, pkt_len - 18 ); /* 设置skb结构 */
            lp->stat.rx_packets ++;
            lp->stat.rx_bytes += pkt_len - 18; /* 统计收到的字节数目 */
            recved ++;
        }
        status = SMC_GET_RX_FIFO_INF() >> 16;/* 读取状态字 */
    }
    if( recved )
        SWI_post( NET_swi_handle );
}

/* 中断处理函数 */
void Smc9218Int( voide )
{
    unsigned int ioaddr;
    unsigned int status, dummy;
    unsigned int iface;

	for( iface = 0; iface < iface_num; iface++)
	{
		if( devs[iface].func_table != lan9218_driver)
			continue;
		/* 如果属于该驱动 */
		ioaddr = devs[iface].base;
	    dummy = SMC_GET_IRQ_CFG();
	    dummy &= 0xfffffeff; /* 关闭中断 */
	    SMC_SET_IRQ_CFG( dummy );
	    SMC_ACK_INT( 0xffffffff ); /* 回应中断 */
	    status = SMC_GET_INT();
	    if ( status & INT_STS_RSFL_ )
	        smc9218_rcv( &devs[iface] );
	    dummy |= 0x100; /* 重新打开中断 */
	    SMC_SET_IRQ_CFG( dummy );				
	}
    return;
}

unsigned int mii_check_media ( struct mii_if_info * mii,
    int init_media )
{
    unsigned int old_carrier, new_carrier;
    int advertise, lpa, media, duplex;
    int lpa2 = 0;

    /* if forced media, go no further */
    if ( mii->force_media )
        return 0; /* duplex did not change */

    /* check current and old link status */
    old_carrier = 0;
    new_carrier = 1;

    /* if carrier state did not change, this is a "bounce",
     * just exit as everything is already set correctly
     */
    if ((! init_media ) && ( old_carrier == new_carrier ))
        return 0; /* duplex did not change */

    /*
     * we have carrier, see who's on the other end
     */

    /* get MII advertise and LPA values */
    if ((! init_media ) && ( mii->advertising ))
        advertise = mii->advertising;
    else {
        advertise = mii->mdio_read( mii->dev, mii->phy_id, MII_ADVERTISE );
        mii->advertising = advertise;
    }
    lpa = mii->mdio_read( mii->dev, mii->phy_id, MII_LPA );
    if ( mii->supports_gmii )
        lpa2 = mii->mdio_read( mii->dev, mii->phy_id, MII_STAT1000 );

    /* figure out media and duplex from advertise and LPA values */
    media = mii_nway_result( lpa & advertise );
    duplex = ( media & ADVERTISE_FULL ) ? 1 : 0;
    if ( lpa2 & LPA_1000FULL )
        duplex = 1;

    if (( init_media ) || ( mii->full_duplex != duplex )) {
        mii->full_duplex = duplex;
        return 1; /* duplex changed */
    }

    return 0; /* duplex did not change */
}

static inline unsigned int mii_nway_result ( unsigned int negotiated )
{
    unsigned int ret;

    if ( negotiated & LPA_100FULL )
        ret = LPA_100FULL;
    else if ( negotiated & LPA_100BASE4 )
        ret = LPA_100BASE4;
    else if ( negotiated & LPA_100HALF )
        ret = LPA_100HALF;
    else if ( negotiated & LPA_10FULL )
        ret = LPA_10FULL;
    else
        ret = LPA_10HALF;

    return ret;
}

static int set_promisc( struct ei_device * ei_local )
{
    unsigned int cr;
    unsigned int ioaddr = ei_local->base;
    SMC_GET_MAC_CR( cr );
    cr |= MAC_CR_PRMS_;
    SMC_SET_MAC_CR( cr );
    return 0;
}

⌨️ 快捷键说明

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