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

📄 ncvirtep.c

📁 CE下 NET2778 NDIS Drivers, 在每个平台上都可以使用
💻 C
📖 第 1 页 / 共 4 页
字号:
///////////////////////////////////////////////////////////////////////////////
STATIC BOOL
RxActivePacketsTest(
    PNC_ENDPOINT_OBJECT Endpoint
    )
{   // A USB OUT (Rx) endpoint is busy if it has packets in the endpoint
    NCBYTE EpStat0;
    DBG_UNREFERENCED_PARAMETER(Endpoint);

    ASSERT(NETCHIP_READ(PAGESEL) == Endpoint->Priv.PhysEp);
    EpStat0 = NETCHIP_READ(EP_STAT0);
    HISTO(DEFAULT_HISTORY, "RxBz", NCHISTO_TRANSFER(Endpoint), EpStat0, NETCHIP_READ(EP_BUFF_STATES));
    return (EpStat0 & (1<<DATA_PACKET_RECEIVED_INTERRUPT))? TRUE: FALSE;
}

///////////////////////////////////////////////////////////////////////////////
typedef enum _NC_REASSIGNMENT_CANDIDATE
{
    ReassignmentCandidate_Invalid = 0,              // Error: No level assigned
    ReassignmentCandidate_Locked,                   // Endpoint cannot be reassigned
    ReassignmentCandidate_ContainsPackets,          // Endpoint content must be saved before re-assigning
    ReassignmentCandidate_OutEpNowContainsPackets,  // OUT endpoint now contains packets (it didn't at first!)
    ReassignmentCandidate_ZeroPackets,              // Endpoint contains no packets
    ReassignmentCandidate_BestChoice,               // Best endpoint choice
} NC_REASSIGNMENT_CANDIDATE, *PNC_REASSIGNMENT_CANDIDATE;

///////////////////////////////////////////////////////////////////////////////
NCSTATUS
ReassignBestEndpoint(
    PNC_ENDPOINT_OBJECT NextEndpoint
    )
{   // Choose the best physical endpoint to unassign, then reassign it to the Next Endpoint
    //  - Return Unsuccessful if reassignment NOT made (e.g. all endpoints locked)

    PNC_ENDPOINT_OBJECT Endpoint = NULL;
    PNC_ENDPOINT_OBJECT E;

    NCBYTE BestEp, PhysEp, StartEp, StopEp, EpIncrement;

    HISTO(DEFAULT_HISTORY, "Rea(", NCHISTO_TRANSFER(NextEndpoint), 0, 0);
    HISTO(DEFAULT_HISTORY, "Cndi", NCHISTO_TRANSFER(PhysicalEndpoints[EPA]), NCHISTO_TRANSFER(PhysicalEndpoints[EPB]), NCHISTO_TRANSFER(PhysicalEndpoints[EPC]));
    BestEp = (PhysicalEndpoints[EPC]->Priv.SwapCandidate > PhysicalEndpoints[EPB]->Priv.SwapCandidate)? EPC: EPB;
    BestEp = (PhysicalEndpoints[BestEp]->Priv.SwapCandidate > PhysicalEndpoints[EPA]->Priv.SwapCandidate)? BestEp: EPA;

    ///////////////////////////////////////////////////////////////////////////
    // First test: If all endpoints are locked, none of the endpoints can be reassigned
    if (PhysicalEndpoints[BestEp]->Priv.SwapCandidate == SwapCandidate_Locked)
    {   // All candidate levels are the same as this one: Locked!
        //  - Unable to reassign endpoint
        //  - Clear virtual endpoint interrupt bit in VIRTOUT0, VIRTOUT1, VIRTIN0, or VIRTIN1
        NETCHIP_WRITE(NextEndpoint->Priv.NcVirtReg, NextEndpoint->Priv.NcVirtBitMask);
        NC_STATISTIC(Reassign_AllLocked++;)
        return NCSTATUS_UNSUCCESSFUL;
    }

    if (PhysicalEndpoints[BestEp]->Priv.SwapCandidate == SwapCandidate_Instant)
    {   // The Best Endpoint can be reassigned instantly:
        Endpoint = PhysicalEndpoints[BestEp];

        // Endpoint reconfiguration will complete quickly, however it will be delayed if 
        // there is traffic on any endpoint
        HISTO(DEFAULT_HISTORY, "Inst", NCHISTO_TRANSFER(Endpoint), NCHISTO_TRANSFER(NextEndpoint), 0);
        NC_STATISTIC(Endpoint->Priv.Reassign_Instantly++;)
        EpReconfigureAndWait(Endpoint, 0<<ENDPOINT_ENABLE);
        goto ReassignInstantly;
    }

    if (NextEndpoint->DirectionIn)
    {   // Next transfer is a USB IN transfer
        //  - Coax this IN transfer to re-assign starting at EPA and work towards EPC
        //  - Apply same order as found in array of Physical Transfers
        StartEp = EPA;
        StopEp = EPC + 1;
        EpIncrement = 1;
    }
    else
    {   // Next transfer is a USB OUT transfer
        //  - Coax this OUT transfer to re-assign starting at EPC and work towards EPA
        //  - Reverse search order 
        StartEp = EPC;
        StopEp = EPA - 1;
        EpIncrement = (NCBYTE)-1;
    }

    ///////////////////////////////////////////////////////////////////////////
    // Choosing an endpoint to reassign: Strategy notes...
    //  - We are now committed to choosing an endpoint...
    //  - The best endpoint to reassign is one that currently doesn't contain any
    //    packets. Next, if all endpoints have packets, then a "second best" endpoint is
    //    chosen. The second best choice will require packets to be saved, which takes 
    //    time and possibly requires a call to a client completion handler. The second best
    //    choice is made with help from a "candidacy score" which was assigned elsewhere.
    //  - Try to migrate IN endpoints toward EPA, and OUT endpoints toward EPC. As long as
    //    the top-level interrupt handler handles transfers on EPA, then EPB, then EPC, IN
    //    packets can be taken by the host concurrent with OUT packets being taken by firmware.

    for (PhysEp = StartEp; PhysEp != StopEp; PhysEp += EpIncrement)
    {   // For every endpoint
        //  - Virtualize any endpoint that does not currently contain packets
        E = PhysicalEndpoints[PhysEp];
        ASSERT(E->Priv.PhysEp == PhysEp);
        if (E->Priv.SwapCandidate == SwapCandidate_Locked)
        {   // Locked endpoints cannot be re-assigned
            //  - Leave endpoint enabled
            E->Priv.ReassignmentCandidate = ReassignmentCandidate_Locked;
            continue;
        }

        // Quickly test if endpoint has active packets in it
        NETCHIP_WRITE(PAGESEL, PhysEp);
        if (E->Priv.TestActivePackets(E))
        {   // Endpoint contains packets
            //  - It is NOT the best choice for unassignment
            //  - Leave endpoint enabled
            E->Priv.ReassignmentCandidate = ReassignmentCandidate_ContainsPackets;
            continue;
        }

        // This endpoint does NOT contain packets (at the moment)
        //  - This endpoint is *possibly* the best candidate for virtualization
        //  - Virtualize the endpoint so that it can participate in the
        //    endpoint re-assignment strategy
        //  - An OUT endpoint *may* accept a packet if it is in the middle of
        //    receiving a packet when its Endpoint Enable gets cleared
        //  - Virtualizing takes time. The endpoint is not virtualized until 
        //    Endpoint Enable reads back FALSE. The amount of time it takes
        //    for an endpoint to virtualize depends on wire-level signalling 
        //    on the NET2272 from this moment forward. It could take as long as a full 
        //    packet, as little as IN/NAK or PING/NAK cycle time, or even zero time!
        //  - NET2272 uses a single logic path to virtualize. Specifically, traffic
        //    on any NET2272 endpoint will delay this endpoint's virtualization.
        //  - Once virtualized, traffic on the USB endpoint will cause a corresponding bit 
        //    in one of VIRTOUT0, VIRTOUT1, VIRTIN0, VIRTIN1 to become set
        NETCHIP_WRITE(EP_CFG, E->Priv.EpCfg & ~(1<<ENDPOINT_ENABLE));
        E->Priv.ReassignmentCandidate = ReassignmentCandidate_ZeroPackets;
        Endpoint = E;
        NC_STATISTIC(E->Priv.Reassign_Possible++;)
    }

    if (Endpoint != NULL)
    {   // At least one endpoint does not contain packets (at the moment!)
        //  - Choose the *best* endpoint that does not contain packets
        //  - Also re-test OUT endpoints since a packet may have successfully arrived
        //    after it was tested and commanded to virtualize

        // Wait for the NET2272 to complete virtualization
        //  - NET2272 uses a single logic path to virtualize. Specifically, traffic
        //    on *any* NET2272 endpoint delays virtualization on this endpoint. Since
        //    this was the final endpoint that was commanded to virtualize, it's guaranteed
        //    that *all* virtualized endpoints will complete virtualization when this one completes:
        EpReconfigureAndWait(Endpoint, 0<<ENDPOINT_ENABLE);

        Endpoint = NULL;
        for (PhysEp = StartEp; PhysEp != StopEp; PhysEp += EpIncrement)
        {   // For every endpoint
            //  - Choose the best endpoint that does not contain packets (if any!)
            E = PhysicalEndpoints[PhysEp];
            if (E->Priv.ReassignmentCandidate != ReassignmentCandidate_ZeroPackets)
            {   // Skip endpoints that are locked or contain packets
                continue;
            }

            // When checked *before* virtualizing (above), this endpoint did not contain any
            // packets, and was therefore an excellent choice. However, if it's an OUT
            // endpoint, a packet may have successfully arrived afterwards
            //  - See if a packet arrived after endpoint was commanded to virtualize
            //  - IN endpoints that didn't contain data before virtualizing will 
            //    continue to be empty
            NETCHIP_WRITE(PAGESEL, PhysEp);
            if (
                (!(E->DirectionIn)) &&          // OUT endpoint? (IN endpoints do not need retesting)
                (E->Priv.TestActivePackets(E))  // Endpoint now has a packet?
                )
            {   // A virtualized OUT endpoint, which did not have a packet earlier, now has a packet
                //  - It is not as good a candidate as it was before!
                //  - Note that this OUT endpoint is still virtualized and, like all
                //    other virtualized endpoints, must be evenutally re-enabled, and
                //    any Virtual Interrupt that could have occurred while virtualized, 
                //    cleared.
                HISTO(DEFAULT_HISTORY, "OutP", NCHISTO_TRANSFER(E), 0, 0);
                E->Priv.ReassignmentCandidate = ReassignmentCandidate_OutEpNowContainsPackets;
                NC_STATISTIC(E->Priv.Reassign_OutNowContainsPackets++;)
                continue;
            }

            // This endpoint is the very best choice:
            //  - Endpoint is virtualized and does not contain packets
            //  - Tip: The search order in this loop should migrate re-assignment of IN 
            //    endpoints towards EPA, and OUT endpoints towards EPC
            //  - No need to search further
            E->Priv.ReassignmentCandidate = ReassignmentCandidate_BestChoice;
            E->Priv.Virtualized = TRUE;
            HISTO(DEFAULT_HISTORY, "Best", NCHISTO_TRANSFER(E), E->Priv.ReassignmentCandidate, 0);
            Endpoint = E;
            NC_STATISTIC(E->Priv.Reassign_EmptyEp++;)
            break;
        }
    }

    for (PhysEp = StartEp; PhysEp != StopEp; PhysEp += EpIncrement)
    {   // For every endpoint:
        //  - Renable virtualized endpoints, except the one that will be re-assigned
        E = PhysicalEndpoints[PhysEp];

        switch (E->Priv.ReassignmentCandidate)
        {
        case ReassignmentCandidate_OutEpNowContainsPackets:
        case ReassignmentCandidate_ZeroPackets:
            // Re-enable endpoints that were virtualized, except the one that will be re-assigned
            NETCHIP_WRITE(PAGESEL, E->Priv.PhysEp);
            NETCHIP_WRITE(EP_CFG, E->Priv.EpCfg);
            E->Priv.Virtualized = FALSE;
            // Now that the endpoint is enabled, clear possible virtual endpoint
            // interrupt bit left over in VIRTOUT0, VIRTOUT1, VIRTIN0, or VIRTIN1
            NETCHIP_WRITE(E->Priv.NcVirtReg, E->Priv.NcVirtBitMask);
            HISTO(DEFAULT_HISTORY, "Enbl", NCHISTO_TRANSFER(E), E->Priv.ReassignmentCandidate, 0);
            break;
        default:
            break;
        }
    }

    if (Endpoint == NULL)
    {   // Unfortunately, all unlocked endpoints currently contain packets
        //  - Make a "second-best" choice
        //  - Endpoints containing packets were not virtualized. (Exception: it's 
        //    possible that an OUT endpoint received a packet after being
        //    commanded to virtualize. Such an endpoint contains a packet,
        //    and is also virtualized. This case was detected above.)
        //  - Taking the second best choice takes time: The endpoint must be virtualized,
        //    then the contents of the endpoint must be saved
        Endpoint = PhysicalEndpoints[BestEp];
        EpReconfigureAndWait(Endpoint, 0<<ENDPOINT_ENABLE);
        // Tip: Saving a transfer *could* result in the client's completion handler 
        // getting called (if transfer manages to complete).
        SaveTransfer(Endpoint);
    }

    // Before reassigning IN endpoints: The host may have taken the final packets of 
    // the IN transfer. If so, the transfer must be completed before virtualizing the
    // endpoint because the host won't issue any more tokens for its transfer.
    if (Endpoint->Priv.PioPacketHandler == TxFinalPio)
    {   // The final packets of an IN transfer may (or may not) have been transmitted to the host
        //  - Before reassigning, call the Tx Final routine
        //  - Tip: If the final packets have been taken, the client's completion handler is
        //    called. (That handler is allowed to start a new transfer on this or other endpoints!)
        ASSERT(Endpoint->Priv.Virtualized);
        TxFinalPio(Endpoint);
    }

ReassignInstantly:
    // Save the transfer's endpoint settings and re-assign the physical endpoint to the Next Endpoint
    //  - These endpoint settings will be reapplied when the virtualized endpoint eventually generates
    //    an interrupt and gets re-assigned
    ASSERT(Endpoint->Priv.Virtualized);
    ASSERT(NextEndpoint->Priv.Virtualized);

    PhysEp = Endpoint->Priv.PhysEp;
    NETCHIP_WRITE(PAGESEL, PhysEp);
    Endpoint->Priv.EpRsp = NETCHIP_READ(EP_RSPSET);
    Endpoint->Priv.EpIrqEnb = NETCHIP_READ(EP_IRQENB);

    // Setup to re-assign Endpoint to the Next Endpoint
    ASSERT(NextEndpoint != Endpoint);
    NextEndpoint->Priv.PhysEp = (BYTE)PhysEp;
    PhysicalEndpoints[PhysEp] = NextEndpoint;
    HISTO(DEFAULT_HISTORY, ")Rea", NCHISTO_TRANSFER(Endpoint), NCHISTO_TRANSFER(NextEndpoint), Endpoint->Priv.EpRsp);
    return NCSTATUS_SUCCESS;
}

///////////////////////////////////////////////////////////////////////////////
PNC_ENDPOINT_OBJECT
NcApi_EpCreate(
    NCBYTE LogicalEp,   // Endpoint's ordinal position in configuration (One-based)
    NCBYTE MapToNcEp    // (Optional) Map the logical endpoint to a specific NetChip endpoint
    )
{   // Initialize a virtual endpoint's Transfer Object
    //  - Most values are extracted from the Endpoint Descriptor
    //  - When this transfer is assigned to a physical endpoint, endpoint values
    //    will be applied to the physical endpoint registers...
    //  - Does not apply to Endpoint Zero
    PNC_ENDPOINT_OBJECT Endpoint;
    PUSB_ENDPOINT_DESCRIPTOR EpDescriptor;
    BYTE UsbEp;
    UINT VirtReg;

    // API for the NET2272 does not support endpoint mapping:
    //  - All NET2272 endpoints are uniform so mapping NetChip endpoints to USB endpoints
    //    is not advantageous. (The API for NET2280, with its non-uniform and dedicated 
    //    endpoints, supports endpoint mapping.)
    DBG_UNREFERENCED_PARAMETER(MapToNcEp);
    ASSERT(MapToNcEp == NC_DEFAULT_ENDPOINT_MAPPING);

    ASSERT(LogicalEp > EP0);  // Endpoint Zero is created by default, in One Time Init, not here!
    ASSERT(LogicalEp <= PrivDeviceObject->ConfigurationEndpointCount);
    Endpoint = &LogicalEndpoints[LogicalEp];

⌨️ 快捷键说明

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