📄 ncvirtep.c
字号:
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 + -