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

📄 physet.c

📁 e100bex网卡驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
//              driver will skip the speed and duplex over-ride code, and
//              assume the adapter is automatically setting the line speed, and
//              the duplex mode.  At the end of this routine, any truly Phy
//              specific code will be executed (each Phy has its own quirks,
//              and some require that certain special bits are set).
//
//   NOTE:  The driver assumes that SPEED and FORCEFDX are specified at the
//          same time. If FORCEDPX is set without speed being set, the driver
//          will encouter a fatal error and log a message into the event viewer.
//
// Arguments:
//      Adapter - ptr to Adapter object instance
//
// Result:
// Returns:
//      TRUE - If the phy could be configured correctly
//      FALSE - If the phy couldn't be configured correctly, because an
//              unsupported over-ride option was used
//-----------------------------------------------------------------------------

BOOLEAN
SetupPhy(
         IN PD100_ADAPTER Adapter
         )

{
    USHORT      MdiControlReg, MdiStatusReg, MdiIdLowReg, MdiIdHighReg;
    USHORT      MdiMiscReg;
    USHORT      LastMdiMiscReg;
    UINT        PhyId;
    BOOLEAN     ForcePhySetting = FALSE;
    UINT        i;

    DEBUGFUNC("SetupPhy");

    INITSTR(("\n"));

    // If we are NOT forcing a setting for line speed or full duplex, then
    // we won't force a link setting, and we'll jump down to the phy
    // specific code.
    if (((Adapter->AiTempSpeed) || (Adapter->AiForceDpx)))
    {
        // Find out what kind of technology this Phy is capable of.
        MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, &MdiStatusReg);

        // Read the MDI control register at our phy
        MdiRead(Adapter, MDI_CONTROL_REG, Adapter->PhyAddress, &MdiControlReg);

        // Now check the validity of our forced option.  If the force option is
        // valid, then force the setting.  If the force option is not valid,
        // we'll set a flag indicating that we should error out.

        // If speed is forced to 10mb
        if (Adapter->AiTempSpeed == 10)
        {
            // If half duplex is forced
            if (Adapter->AiForceDpx == 1)
            {
                if (MdiStatusReg & MDI_SR_10T_HALF_DPX)
                {
                    INITSTR(("Forcing 10mb 1/2 duplex\n"));
                    MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
                    ForcePhySetting = TRUE;
                }
            }

            // If full duplex is forced
            else if (Adapter->AiForceDpx == 2)
            {
                if (MdiStatusReg & MDI_SR_10T_FULL_DPX)
                {
                    INITSTR(("Forcing 10mb full duplex\n"));
                    MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT);
                    MdiControlReg |= MDI_CR_FULL_HALF;
                    ForcePhySetting = TRUE;
                }
            }

            // If auto duplex (we actually set phy to 1/2)
            else
            {
                if (MdiStatusReg & (MDI_SR_10T_FULL_DPX | MDI_SR_10T_HALF_DPX))
                {
                    INITSTR(("Forcing 10mb auto duplex\n"));
                    MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
                    ForcePhySetting = TRUE;
                    Adapter->AiForceDpx = 1;
                }
            }
        }

        // If speed is forced to 100mb
        else if (Adapter->AiTempSpeed == 100)
        {
            // If half duplex is forced
            if (Adapter->AiForceDpx == 1)
            {
                if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE))
                {
                    INITSTR(("Forcing 100mb half duplex\n"));
                    MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
                    MdiControlReg |= MDI_CR_10_100;
                    ForcePhySetting = TRUE;
                }
            }

            // If full duplex is forced
            else if (Adapter->AiForceDpx == 2)
            {
                if (MdiStatusReg & MDI_SR_TX_FULL_DPX)
                {
                    INITSTR(("Forcing 100mb full duplex\n"));
                    MdiControlReg &= ~MDI_CR_AUTO_SELECT;
                    MdiControlReg |= (MDI_CR_10_100 | MDI_CR_FULL_HALF);
                    ForcePhySetting = TRUE;
                }
            }

            // If auto duplex (we set phy to 1/2)
            else
            {
                if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE))
                {
                    INITSTR(("Forcing 100mb auto duplex\n"));
                    MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
                    MdiControlReg |= MDI_CR_10_100;
                    ForcePhySetting = TRUE;
                    Adapter->AiForceDpx = 1;
                }
            }
        }

        if (ForcePhySetting == FALSE)
        {
            INITSTR(("Can't force speed=%d, duplex=%d\n",Adapter->AiTempSpeed, Adapter->AiForceDpx));

            D100LogError(Adapter, EVENT_9, NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, 0);

            return (FALSE);
        }

        // Write the MDI control register with our new Phy configuration
        MdiWrite(Adapter, MDI_CONTROL_REG, Adapter->PhyAddress, MdiControlReg);

        // wait 100 milliseconds for auto-negotiation to complete
        D100StallExecution(100);

    }


    // Find out specifically what Phy this is.  We do this because for certain
    // phys there are specific bits that must be set so that the phy and the
    // 82557 work together properly.

    MdiRead(Adapter, PHY_ID_REG_1, Adapter->PhyAddress, &MdiIdLowReg);
    MdiRead(Adapter, PHY_ID_REG_2, Adapter->PhyAddress, &MdiIdHighReg);

    PhyId =  ((UINT) MdiIdLowReg | ((UINT) MdiIdHighReg << 16));
    Adapter->PhyId = PhyId;

    INITSTR(("Phy ID is %x\n", PhyId));

    // And out the revsion field of the Phy ID so that we'll be able to detect
    // future revs of the same Phy.
    PhyId &= PHY_MODEL_REV_ID_MASK;

    // Handle the National TX
    if (PhyId == PHY_NSC_TX)
    {
        INITSTR(("Found a NSC TX Phy\n"));

        MdiRead(Adapter, NSC_CONG_CONTROL_REG, Adapter->PhyAddress, &MdiMiscReg);

        MdiMiscReg |= (NSC_TX_CONG_TXREADY | NSC_TX_CONG_F_CONNECT);

        // If we are configured to do congestion control, then enable the
        // congestion control bit in the National Phy
        if (Adapter->Congest)
            MdiMiscReg |= NSC_TX_CONG_ENABLE;
        else
            MdiMiscReg &= ~NSC_TX_CONG_ENABLE;

        MdiWrite(Adapter, NSC_CONG_CONTROL_REG, Adapter->PhyAddress, MdiMiscReg);
    }

    FindPhySpeedAndDpx(Adapter, PhyId);

    INITSTR(("Current speed=%d, Current Duplex=%d\n",Adapter->AiLineSpeedCur, Adapter->AiDuplexCur));

    return (TRUE);
}


//-----------------------------------------------------------------------------
// Procedure:   FindPhySpeedAndDpx
//
// Description: This routine will figure out what line speed and duplex mode
//              the PHY is currently using.
//
// Arguments:
//      Adapter - ptr to Adapter object instance
//      PhyId - The ID of the PHY in question.
//
// Returns:
//      NOTHING
//-----------------------------------------------------------------------------

VOID
FindPhySpeedAndDpx(
                   IN PD100_ADAPTER Adapter,
                   IN UINT PhyId
                   )

{
    USHORT      MdiStatusReg, MdiMiscReg, MdiOwnAdReg, MdiLinkPartnerAdReg;

    DEBUGFUNC("FindPhySpeedAndDpx");

    INITSTR(("\n"));

    // If there was a speed and/or duplex override, then set our current
    // value accordingly
    Adapter->AiLineSpeedCur = Adapter->AiTempSpeed;
    Adapter->AiDuplexCur = (USHORT) Adapter->AiForceDpx;

    // If speed and duplex were forced, then we know our current settings, so
    // we'll just return.  Otherwise, we'll need to figure out what NWAY set
    // us to.
    if (Adapter->AiLineSpeedCur && Adapter->AiDuplexCur)
        return;

    // If we didn't have a valid link, then we'll assume that our current
    // speed is 10mb half-duplex.

    // Read the status register twice because of sticky bits
    MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, &MdiStatusReg);
    MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, &MdiStatusReg);

    // If there wasn't a valid link then use default speed & duplex
    if (!(MdiStatusReg & MDI_SR_LINK_STATUS))
    {
        INITSTR(("Link Not found for speed detection!!!  Using defaults.\n"));

        Adapter->AiLineSpeedCur = 10;
        Adapter->AiDuplexCur = 1;

        return;
    }

    // If this is an Intel PHY (a T4 PHY_100 or a TX PHY_TX), then read bits
    // 1 and 0 of extended register 0, to get the current speed and duplex
    // settings.
    if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || (PhyId == PHY_TX_ID))
    {
        INITSTR(("Detecting Speed/Dpx for an Intel PHY\n"));

        // Read extended register 0
        MdiRead(Adapter, EXTENDED_REG_0, Adapter->PhyAddress, &MdiMiscReg);

        // Get current speed setting
        if (MdiMiscReg & PHY_100_ER0_SPEED_INDIC)
            Adapter->AiLineSpeedCur = 100;
        else
            Adapter->AiLineSpeedCur = 10;

        // Get current duplex setting -- if bit is set then FDX is enabled
        if (MdiMiscReg & PHY_100_ER0_FDX_INDIC)
            Adapter->AiDuplexCur = 2;
        else
            Adapter->AiDuplexCur = 1;

        return;
    }

    // Read our link partner's advertisement register
    MdiRead(Adapter, AUTO_NEG_LINK_PARTNER_REG, Adapter->PhyAddress, &MdiLinkPartnerAdReg);

    // See if Auto-Negotiation was complete (bit 5, reg 1)
    MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, &MdiStatusReg);

    // If a True NWAY connection was made, then we can detect speed/duplex by
    // ANDing our adapter's advertised abilities with our link partner's
    // advertised ablilities, and then assuming that the highest common
    // denominator was chosed by NWAY.
    if ((MdiLinkPartnerAdReg & NWAY_LP_ABILITY) &&
        (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE))
    {
        INITSTR(("Detecting Speed/Dpx from NWAY connection\n"));


        // Read our advertisement register
        MdiRead(Adapter, AUTO_NEG_ADVERTISE_REG, Adapter->PhyAddress, &MdiOwnAdReg);


        // AND the two advertisement registers together, and get rid of any
        // extraneous bits.
        MdiOwnAdReg &= (MdiLinkPartnerAdReg & NWAY_LP_ABILITY);

        // Get speed setting
        if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX | NWAY_AD_TX_FULL_DPX | NWAY_AD_T4_CAPABLE))
            Adapter->AiLineSpeedCur = 100;
        else
            Adapter->AiLineSpeedCur = 10;

        // Get duplex setting -- use priority resolution algorithm
        if (MdiOwnAdReg & (NWAY_AD_T4_CAPABLE))
        {
            Adapter->AiDuplexCur = 1;
            return;
        }
        else if (MdiOwnAdReg & (NWAY_AD_TX_FULL_DPX))
        {
            Adapter->AiDuplexCur = 2;
            return;
        }
        else if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX))
        {
            Adapter->AiDuplexCur = 1;
            return;
        }
        else if (MdiOwnAdReg & (NWAY_AD_10T_FULL_DPX))
        {
            Adapter->AiDuplexCur = 2;
            return;
        }
        else
        {
            Adapter->AiDuplexCur = 1;
            return;
        }
    }

    // If we are connected to a non-NWAY repeater or hub, and the line
    // speed was determined automatically by parallel detection, then we have
    // no way of knowing exactly what speed the PHY is set to unless that PHY
    // has a propietary register which indicates speed in this situation.  The
    // NSC TX PHY does have such a register.  Also, since NWAY didn't establish
    // the connection, the duplex setting should HALF duplex.

    Adapter->AiDuplexCur = 1;

    if (PhyId == PHY_NSC_TX)
    {
        INITSTR(("Detecting Speed/Dpx from non-NWAY NSC connection\n"));

        // Read register 25 to get the SPEED_10 bit
        MdiRead(Adapter, NSC_SPEED_IND_REG, Adapter->PhyAddress, &MdiMiscReg);

        // If bit 6 was set then we're at 10mb
        if (MdiMiscReg & NSC_TX_SPD_INDC_SPEED)
            Adapter->AiLineSpeedCur = 10;
        else
            Adapter->AiLineSpeedCur = 100;
    }

    // If we don't know what line speed we are set at, then we'll default to
    // 10mbs
    else
        Adapter->AiLineSpeedCur = 10;

}


//-----------------------------------------------------------------------------
// Procedure:   ResetPhy
//
// Description: This routine will reset the PHY that the adapter is currently
//              configured to use.
//
// Arguments:
//      Adapter - ptr to Adapter object instance
//
// Returns:
//      NOTHING
//-----------------------------------------------------------------------------

VOID
ResetPhy(
         IN PD100_ADAPTER Adapter
         )

{
    USHORT      MdiControlReg;

    DEBUGFUNC("ResetPhy");

    INITSTR(("\n"));

    DEBUGCHAR(Adapter,'P');
    // Reset the Phy, enable auto-negotiation, and restart auto-negotiation.
    MdiControlReg = (MDI_CR_AUTO_SELECT | MDI_CR_RESTART_AUTO_NEG | MDI_CR_RESET);

    // Write the MDI control register with our new Phy configuration
    MdiWrite(Adapter, MDI_CONTROL_REG, Adapter->PhyAddress, MdiControlReg);
}

⌨️ 快捷键说明

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