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

📄 ncvirtep.c

📁 CE下 NET2778 NDIS Drivers, 在每个平台上都可以使用
💻 C
📖 第 1 页 / 共 4 页
字号:

    EpDescriptor = Endpoint->EpDescriptor;
    ASSERT(EpDescriptor != NULL);
    ASSERT(EpDescriptor->bDescriptorType == ENDPOINT_DESC);
    ASSERT(EpDescriptor->bmAttributes != CTRL);
    UsbEp = EpDescriptor->bEndpointAddress;
    ASSERT((UsbEp & 0x0f) != 0);  // This routine does not apply to Endpoint Zero

    // Determine which VIRTXXXX register (one of VIRTOUT0, VIRTOUT1, VIRTIN0, VIRTIN1)
    // and bit mask applies to the USB endpoint endpoint address
    //  - This is an odd, contorted section, and may be difficult to follow. It relies on
    //    on the layout of the NET2272 VIRTXXXX registers. See the NET2272 spec for details
    VirtReg = (UsbEp & (1<<EP_DIRECTION_IN))? VIRTIN0: VIRTOUT0;    // VIRTINx or VIRTOUTx regs?
    VirtReg += (UsbEp & (1<<3))? 1: 0;                              // VIRTxxx1 or VIRTxxx0 regs?
    ASSERT((VirtReg >= VIRTOUT0) && (VirtReg <= VIRTIN1));
    Endpoint->Priv.NcVirtReg = (BYTE)VirtReg;
    // Determine a bit mask within the VIRTXXX register to use to test for a "NAK returned to host"
    // condition for the USB endpoint
    Endpoint->Priv.NcVirtBitMask = (BYTE)(1<<(UsbEp & 0x07));

    // Extract values from the endpoint descriptor that will be applied to
    // endpoint and transfer programming:
    Endpoint->DirectionIn = UsbEp & (1<<EP_DIRECTION_IN);
    if (Endpoint->DirectionIn)
    {   // USB IN (Tx)
        Endpoint->Priv.PioPacketHandler = TxPacketsPio;                         // Data transfer handler
        NC_VIRT_EP(Endpoint->Priv.TestActivePackets = TxActivePacketsTest;)     // Reassignment test handler
    }
    else
    {   // USB OUT (Rx)
        Endpoint->Priv.PioPacketHandler = RxPacketsPio;                         // Data transfer handler
        NC_VIRT_EP(Endpoint->Priv.TestActivePackets = RxActivePacketsTest);     // Reassignment test handler
    }

    Endpoint->Priv.EpCfg = (BYTE)(
        (EpDescriptor->bEndpointAddress & 0x0f) |                   // USB endpoint address (not including endpoint direction)
        (EpDescriptor->bmAttributes<<ENDPOINT_TYPE) |               // USB endpoint type (BULK, INTR, ...)
        ((EpDescriptor->bEndpointAddress & (1<<EP_DIRECTION_IN))?   // USB direction (IN, OUT)
            (1<<ENDPOINT_DIRECTION): 
            (0<<ENDPOINT_DIRECTION)) |
        (1<<ENDPOINT_ENABLE) |                                      // Enable 
        0);
    Endpoint->Priv.EpRsp =
        (1<<AUTOVALIDATE) |                                         // Applies to USB IN (Tx) 
        (1<<NAK_OUT_PACKETS_MODE) |                                 // Applies to USB OUT (Rx)
        0;

    // Performance: For fast reference, extract endpoint's Max Packet Size 
    // from the endpoint descriptor:
    //  - Tip: Awkward syntax is for portability to Big Endian CPU's (USB is Little Endian)
    Endpoint->Priv.EpMaxPkt.Byte[MYEND_LO] = EpDescriptor->wMaxPacketSizeLo;
    Endpoint->Priv.EpMaxPkt.Byte[MYEND_HI] = EpDescriptor->wMaxPacketSizeHi;
    Endpoint->CompletionStatus = NCSTATUS_SUCCESS;

    // Virtual endpoint lock time limit
    //  - Time lock help control excessive and unproductive endpoint reassignment
    //  - Specify reasonable defaults now...
    //  - Client can change defaults before starting (but not during!) a transfer
    //  - Lock the endpoint for minimum of this many USB frames
    Endpoint->Ex.VirtualEp_MinLockTime = NCPRIV_MIN_LOCK_TIME;

    if (LogicalEp < PHYSICAL_ENDPOINT_COUNT)
    {   // Logical endpoint is within the NET2272 range of physical endpoints
        //  - Program physical endpoints according to the first few logical endpoint settings
        //  - This is like dynamic endpoint save-and-restart (except nothing needs to be saved 
        //    first, and there is no transfer to restart). This initialization technique
        //    makes saving, reassigning and restoring endpoints faster.
        ASSERT(Endpoint->Priv.PhysEp == LogicalEp);
        ASSERT(Endpoint->Priv.SwapCandidate == SwapCandidate_TransferComplete);
        NETCHIP_WRITE(PAGESEL, LogicalEp);
        ASSERT(!(NETCHIP_READ(EP_CFG) & (1<<ENDPOINT_ENABLE)));
        ASSERT(NETCHIP_READ(EP_IRQENB) == 0);

        NETCHIP_WRITE(EP_STAT0,
            (1<<NAK_OUT_PACKETS) |                      // Required!
            (1<<SHORT_PACKET_TRANSFERRED_INTERRUPT) |   // Info only
            (1<<DATA_PACKET_RECEIVED_INTERRUPT) |       // Required!
            (1<<DATA_PACKET_TRANSMITTED_INTERRUPT) |    // Required!
            (1<<DATA_OUT_TOKEN_INTERRUPT) |             // Info only 
            (1<<DATA_IN_TOKEN_INTERRUPT) |              // Required (for token notification)
            0);

        // Set Buffer Flush to get rid of any junk data in the buffers
        NETCHIP_WRITE(EP_STAT1, 
            (1<<BUFFER_FLUSH) |                         // Required!
            (1<<LOCAL_OUT_ZLP) |                        // Info only
            (1<<USB_STALL_SENT) |                       // Info only
            (1<<USB_IN_NAK_SENT) |                      // Info only
            (1<<USB_IN_ACK_RCVD) |                      // Info only
            (1<<USB_OUT_NAK_SENT) |                     // Info only
            (1<<USB_OUT_ACK_SENT) |                     // Info only
            (1<<TIMEOUT) |                              // Info only
            0);

        // Set up endpoint registers
        NETCHIP_WRITE(EP_MAXPKT0, Endpoint->Priv.EpMaxPkt.Byte[MYEND_LO]);
        NETCHIP_WRITE(EP_MAXPKT1, Endpoint->Priv.EpMaxPkt.Byte[MYEND_HI]);
        NETCHIP_WRITE(EP_RSPCLR, ~(Endpoint->Priv.EpRsp));

        // Set Alternative NAK OUT Packets, along with other EP_RSP bits
        //  - Ensure that OUT packets on this physical endpoint will be NAK'd.
        //  - Otherwise, if data arrives in the endpoint, but there is no Transfer Object
        //    for the endpoint's data, the endpoint cannot be reassigned!
        Endpoint->Priv.EpRsp |= (1<<ALT_NAK_OUT_PACKETS);
        NETCHIP_WRITE(EP_RSPSET, Endpoint->Priv.EpRsp);

        // Assign transfer for the USB endpoint to this physical endpoint
        //  - When the USB endpoint is assigned to the NET2272 physical endpoint,
        //    the USB endpoint is no longer 'virtualized'. That means the associated
        //    virtualization bit (in VIRTOUT0, VIRTOUT1, VIRTIN0, or VIRTIN1) can no
        //    longer be set by the host's request for the USB endpoint
        NC_VIRT_EP(EpReconfigureAndWait(Endpoint, 1<<ENDPOINT_ENABLE));

        // Clear virtual endpoint interrupt bit in VIRTOUT0, VIRTOUT1, VIRTIN0, or VIRTIN1
        NETCHIP_WRITE(Endpoint->Priv.NcVirtReg, Endpoint->Priv.NcVirtBitMask);
    }
    else
    {   // Endpoint is virtualized
        Endpoint->Priv.Virtualized = TRUE;
        NETCHIP_WRITE(USBCTL1, NETCHIP_READ(USBCTL1) | (1<<VIRTUAL_ENDPOINT_ENABLE));
    }

#if _NCDEBUG || _NCHISTO || _NCSTATISTICS
    Endpoint->Priv.UsbEp = Endpoint->EpDescriptor->bEndpointAddress;
#endif
    HISTO(DEFAULT_HISTORY, "TIni", NCHISTO_TRANSFER(Endpoint), Endpoint->Priv.NcVirtReg, Endpoint->Priv.NcVirtBitMask);
    return Endpoint;
}

///////////////////////////////////////////////////////////////////////////////
NCSTATUS
NcApi_EpTransfer(
    PNC_ENDPOINT_OBJECT Endpoint
    )
{   // Start a transfer on an endpoint
    //  - Applies to all endpoint directions and types, including Endpoint Zero
    //  - Except for Endpoint Zero, it is safe to call here from the client's 
    //    transfer completion handler
    PNC_TRANSFER_OBJECT Transfer;

    ASSERT(Endpoint != NULL);
    Transfer = Endpoint->Transfer;
    ASSERT(Endpoint->Transfer != NULL);

    ASSERT(Transfer->ClientCompletionHandler != NULL);
    ASSERT(Endpoint->CompletionStatus != NCSTATUS_PENDING);

#if _NCDEBUG
    // Extra checks on client request:
    //  - These checks help ensure compatibility across NetChip's family of firmware API's
    switch (Transfer->TransferFlags & ~(
        (1<<NC_TRANSFER_FLAG_APPLY_PIO) |
        (1<<NC_TRANSFER_FLAG_TRANSFER_LOCK) |
        (1<<NC_TRANSFER_FLAG_ENDPOINT_LOCK) |
        0))
    {
    case (1<<NC_TRANSFER_FLAG_TOKEN_NOTIFICATION):
        // Token notification: PIO must also be set; no other flags or length
        ASSERT(Transfer->TransferFlags & (1<<NC_TRANSFER_FLAG_APPLY_PIO));
        ASSERT(Transfer->TransferSize == 0);
        break;
    case (1<<NC_TRANSFER_FLAG_APPLY_CONCATENATION):
        // Concatenation only applies to IN transfers. (Concatenation is implied for OUT transfers)
        //  - Transfer or Endpoint Lock must be TRUE (since there is no place to rewind concatenated fragments!)
        //  - Other flags are expected to be FALSE
        //  - Transfer Size is expected to be non-zero
        ASSERT(Transfer->TransferFlags & ((1<<NC_TRANSFER_FLAG_TRANSFER_LOCK) | (1<<NC_TRANSFER_FLAG_ENDPOINT_LOCK)));
        ASSERT(Transfer->TransferSize != 0);
        ASSERT(Endpoint->DirectionIn);
        ASSERT(Transfer->TransferBuffer != NULL);
#if NET2272_16BIT
        // When NET2272 configured for 16 bit bus, concatenating transfer size must be even
        ASSERT(!(Transfer->TransferSize & 1))
#endif
        // Drop through!
    case (1<<NC_TRANSFER_FLAG_APPLY_ZLP):
    case 0:
        break;
    default:
        // Client's flag setting is not accepted
        NCPRINTF(VOLUME_MINIMUM, ("NcApi_EpTransfer(): Transfer flag setting not accepted:%2.2x\n",
            Transfer->TransferFlags
            ));
        NCFAULT();
        break;
    }
#endif

    // Partial transfer handling is a client option:
    //  - If client didn't specify a partial transfer handler, apply a "Do Nothing" handler
    //  - Porting tip: This method assumes the client may or may not use partial
    //    transfers. All references to partial transfer handling may be optimized
    //    if they are always used or never used. (Tip: Optimize *after* debugging!)
    if (Transfer->PartialTransferHandler == NULL)
    {   // Client has not specified a Partial Transfer Handler
        Transfer->PartialTransferHandler = (void(*)(PNC_ENDPOINT_OBJECT))DoNothing_Void;;
    }

    // Set up transfer starting values
    //  - Copy a few client transfer members to our private section
    Endpoint->Priv.pPkt = (PBYTE)Transfer->TransferBuffer;
    Endpoint->Priv.BytesRemaining = Transfer->TransferSize;
    Endpoint->CompletionStatus = NCSTATUS_PENDING;          // NcApi now owns this structure

	// Setup initial interrupt enables:
	//  - One interrupt enable for IN another for OUT
	//  - No need to differentiate IN from OUT endpoints
    Endpoint->Priv.EpIrqEnb = (
        (1<<DATA_IN_TOKEN_INTERRUPT_ENABLE) |			// Tx (USB IN): Token indicating host is *requesting* packets
        (1<<DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) |	// Rx (USB OUT): Packet(s) have actually been received
        0);

    HISTO(DEFAULT_HISTORY, "Xfr", NCHISTO_TRANSFER(Endpoint), Endpoint->Priv.pPkt, Endpoint->Priv.BytesRemaining);

    // PAGESEL and IRQENB registers may be modified, so the following section must 
    // either be protected from interrupts or run in an interrupt context
    NC_INTERRUPT_SENSITIVE_SECTION_START

    if (Endpoint->Priv.Virtualized)
    {   // Endpoint is virtualized
        //  - Virtual Endpoint Interrupt Enable may have been cleared (if the virtual interrupt
        //    handler determined that no virtual endpoints could be serviced)
        NETCHIP_WRITE(IRQENB0, 
            NETCHIP_READ(IRQENB0) |
            (1<<VIRTUALIZED_ENDPOINT_INTERRUPT_ENABLE) |
            0);
    }
    else
    {   // Physical endpoint is currently assigned
        //  - Enable physical endpoint interrupts to start the transfer immediately.
        //  - Special note for USB IN (Tx) transfers: Data IN Token Interrupt Enable is
        //    set to cause the interrupt handler to run when the host starts the IN 
        //    transfer (if it hasn't already started!). This has no effect on OUT
        //    endpoints. The Tx interrupt handler should clear Data IN Token Interrupt 
        //    Enable to prevent unwanted interrupts due to IN tokens
        NETCHIP_WRITE(PAGESEL, Endpoint->Priv.PhysEp);
        // Assert: This assert applies when virtualizing endpoints; it cannot be applied to EP0:
        ASSERT(((NETCHIP_READ(EP_CFG) & ~(1<<ENDPOINT_ENABLE)) == (Endpoint->Priv.EpCfg & ~(1<<ENDPOINT_ENABLE))) || (Endpoint->Priv.PhysEp == EP0));

        if (Endpoint->DirectionIn)
        {   // IN endpoint:
            //  - Preload as many bytes as possible into the endpoint
            //  - Endpoint Zero: Should never get here (Direction IN must always be FALSE)
            ASSERT(Endpoint->Priv.PhysEp != EP0);
            TxPacketsPio(Endpoint);
        }
        else
        {   // OUT endpoint:
            //  - If NAK OUT Packets (or Alternative NAK OUT Packets) was set from 
            //    a previous transfer it must be cleared (or the endpoint won't 
            //    accept any packets!)
            //  - Tip: If an un-completed transfer accidently gets NAK OUT Packets set, 
            //    the endpoint NAKs FOREVER!
            //  - NAK OUT Packets is managed from EP_RSP
            //  - Endpoint Zero: These settings have no effect
            NETCHIP_WRITE(EP_RSPCLR, Endpoint->Priv.EpRsp & (1<<ALT_NAK_OUT_PACKETS));
            Endpoint->Priv.EpRsp &= ~(1<<ALT_NAK_OUT_PACKETS);

            // Once NAK OUT Packets is cleared, the endpoint can accept packets, so
            // its candidate level must NOT be Short Packet Complete! (Short Packet
            // Complete candidates can be reassigned fast, without checking the endpoint!)
            Endpoint->Priv.SwapCandidate = SwapCandidate_TransferComplete;
            NETCHIP_WRITE(EP_IRQENB, Endpoint->Priv.EpIrqEnb);
        }
    }
    NC_INTERRUPT_SENSITIVE_SECTION_END

    // Endpoint locking:
    if (Transfer->TransferFlags & ((1<<NC_TRANSFER_FLAG_ENDPOINT_LOCK) | (1<<NC_TRANSFER_FLAG_TRANSFER_LOCK)))
    {   // Client is requesting a lock:
        //  - Make sure endpoint can't get reassigned from the very start!
        Endpoint->Priv.SwapCandidate = SwapCandidate_Locked;
    }

    // If a previous transfer on this logical endpoint completed with
    // a short packet, Alternative NAK OUT Packets would be set. It must
    // be cleared so that if it gets reassigned to a physical endpoint
    // it won't have NAK OUT Packets set!
    //  - Changing Alternative NAK OUT Packets has no effect on IN endpoints
    //  - Debug tip: If an un-completed transfer accidently gets NAK OUT Packets 
    //    set, the endpoint NAKs FOREVER!
    Endpoint->Priv.EpRsp &= ~(1<<ALT_NAK_OUT_PACKETS);

    return NCSTATUS_SUCCESS;
}

///////////////////////////////////////////////////////////////////////////////
#endif  // _NCVIRTUALENDPOINTS

///////////////////////////////////////////////////////////////////////////////
//  End of file
///////////////////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

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