📄 ncfwapi.c
字号:
UINT ByteCount, LoopCount;
#if TIMEOUT_CATCHER && _NCDEBUG
// Check for USB timeout error
if (NETCHIP_READ(EP_STAT1) & (1<<TIMEOUT))
{ // A USB timeout has occurred
// - At least one retry was required to get the data correctly
// - If you get a lot of timeout errors, you may want to check your signal quality
NCPRINTF(VOLUME_LOW, ("TxPacketsPio(): Warning: Timeout detected on USB EP:%2.2x\n", Endpoint->Priv.PhysEp));
NETCHIP_WRITE(EP_STAT1, 1<<TIMEOUT);
}
#endif
// Clear interrupt status
// - Tip: Leave Data IN Token Interrupt set for "self-interrupt" and concatenation
NETCHIP_WRITE(EP_STAT0, (1<<DATA_PACKET_TRANSMITTED_INTERRUPT));
EpStat0 = NETCHIP_READ(EP_STAT0);
if (EpStat0 & 1<<BUFFER_FULL)
{ // Buffer full:
// - There is no room in the endpoint for any more Tx data
// - Exit now and wait for a packet to be taken by the host. When that
// happens, a Data Packet Transmitted Interrupt will occur, then
// there will be room in the endpoint for more data
// - Concatenation: Now that buffers are full, clear Data IN Token
// interrupt to prevent self-interruption. (As packets are taken
// by the host, Data Packet Transmitted interrupts will get transfers
// going again)
NETCHIP_WRITE(EP_STAT0, (1<<DATA_IN_TOKEN_INTERRUPT));
Endpoint->BytesTransferred = Endpoint->Priv.pPkt - (PBYTE)Transfer->TransferBuffer;
HISTO(DEFAULT_HISTORY, "TPrt", EpStat0, NETCHIP_READ(EP_STAT0), Endpoint->BytesTransferred);
// Give client an opportunity to handle partial transfer
// - For instance, client may wish to queue more data from its hardware
Transfer->PartialTransferHandler(Endpoint);
break;
}
// We are now committed to loading data into the endpoint
// - There is data remaining to be transferred
// - There is space available in the endpoint to put that data
NC_LED2(TRUE); // Turn RDK daughter board LED ON
// Determine how many bytes we can copy
EpAvail.Byte[MYEND_LO] = NETCHIP_READ(EP_AVAIL0);
EpAvail.Byte[MYEND_HI] = NETCHIP_READ(EP_AVAIL1);
LoopCount = ByteCount = min(EpAvail.Word, Endpoint->Priv.BytesRemaining);
//XXXXXXXXXXXXX FIX COMMENTS! ALSO APPLIES TO CONCATENATION!!!!!!!
// Virtualization: Prepare for possible "endpoint save" due to virtualization
// - Record number of bytes that will be in the "last packet" of the endpoint.
// - This value may be used by the virtualization section to account for unsent data
Endpoint->Priv.LastPacketSize = (Endpoint->Priv.EpMaxPkt.Word - EpAvail.Word) + ByteCount;
// Transfer accounting
Endpoint->Priv.BytesRemaining -= ByteCount;
Endpoint->Priv.pPkt += ByteCount;
HISTO(DEFAULT_HISTORY, "TxCp", ByteCount, EpAvail.Word, Endpoint->Priv.BytesRemaining);
#if NET2272_16BIT
// Recalculate loop counter for 16 bit accesses
// - Tip: If the Byte Count is an odd number of bytes (1, 3, 5, ...) LoopCount
// will be calculated such that the last byte is not transferred in the
// loop. The last byte is written in a special case below...
LoopCount >>= 1;
#endif
#pragma message(_NC_MESSAGE"Recommendation: Optimize Tx copy loop in assembler")
// Copy bytes to endpoint
// - For best performance, this loop should be optimized, and written in assembler
ASSERT((LoopCount == 0) || (pTxBuf != NULL)); // NULL is OK e.g., for Token Notification
while (LoopCount--)
{
NETCHIP_BASEADDRESS[EP_DATA].NcReg = *(pTxBuf++);
}
if (Endpoint->Priv.BytesRemaining == 0)
{ // No more bytes in this transfer. Handle Short Packet validation issues
// - If the "Apply ZLP" flag is TRUE, then we will validate a short packet
// for any transfer size. Otherwise, we will only validate a short packet
// if the transfer size is NOT an exact max packet multiple
HISTO(DEFAULT_HISTORY, "ZByt", NCHISTO_TRANSFER(Endpoint), NETCHIP_READ(EP_STAT0), Transfer->TransferFlags);
if (Transfer->TransferFlags & (
(1<<NC_TRANSFER_FLAG_APPLY_CONCATENATION) |
(1<<NC_TRANSFER_FLAG_TOKEN_NOTIFICATION) |
0))
{ // Client is either requesting notification of an IN token, or doing concatenation
// - Transfer is complete.
// - For concatenation, some number of bytes may still be left unvalidated
// in the endpoint. The client should start another transfer from its
// completion handler to validate the unsent bytes.
// - If the endpoint holds an exact-packet multiple number of bytes, it
// is automatically validated by the endpoint logic
NETCHIP_WRITE(EP_IRQENB, 0);
Endpoint->BytesTransferred = Endpoint->Priv.pPkt - (PBYTE)Transfer->TransferBuffer;
if ((Endpoint->Priv.LastPacketSize % Endpoint->Priv.EpMaxPkt.Word) == 0)
{ // Endpoint contains an exact-packet multiple
// - Endpoint hardware automatically validates the packet
Endpoint->CompletionStatus = NCSTATUS_SUCCESS;
}
else
{ // Endpoint contains a partial packet
// - Request is completing, but the partial packet is not being validated
// - Partial packet is "stuck" in the endpoint
// - The endpoint must remain locked (i.e. it cannot be reassigned)
// until partial packet is validated. This leads to potential deadlock!
// - Client must take further action (i.e. issue another request) to
// validate the partial packet. Recommendation: Client completion handler
// should start another transfer request to validate the endpoint contents
Endpoint->CompletionStatus = NCSTATUS_PARTIAL_PACKET;
NC_VIRT_EP(Endpoint->Priv.SwapCandidate = SwapCandidate_Locked;)
ASSERT(Transfer->TransferFlags & ((1<<NC_TRANSFER_FLAG_TRANSFER_LOCK) | (1<<NC_TRANSFER_FLAG_ENDPOINT_LOCK)));
}
NC_STATISTIC(Endpoint->Priv.TotalBytesTransferred += Endpoint->BytesTransferred;)
NC_STATISTIC(Endpoint->Priv.TotalTransfers++;)
HISTO(DEFAULT_HISTORY, "TorC", NCHISTO_TRANSFER(Endpoint), NETCHIP_READ(EP_STAT0), Endpoint->BytesTransferred);
#if NET2272_16BIT
// Assert: In 16 bit mode, cannot concatenate odd sizes
ASSERT(!(ByteCount & 0x01));
#endif
// Call client's transfer completion handler
// - Client should return from this call as quickly as possible
// - Client may start another transfer on this or another endpoint
Transfer->ClientCompletionHandler(Endpoint);
break;
}
if (
(Transfer->TransferFlags & (1<<NC_TRANSFER_FLAG_APPLY_ZLP)) || // Apply ZLP? (Implies Apply Short Packet!)
(ByteCount < Endpoint->Priv.EpMaxPkt.Word) // Not a Max Packet multiple?
)
{ // Transfer has a short packet (i.e. not a Max Packet multiple) or ZLP is to be applied
WORDBYTE EpAvail;
EpAvail.Byte[MYEND_LO] = NETCHIP_READ(EP_AVAIL0);
EpAvail.Byte[MYEND_HI] = NETCHIP_READ(EP_AVAIL1);
HISTO(DEFAULT_HISTORY, "SorZ", NCHISTO_TRANSFER(Endpoint), NETCHIP_READ(EP_STAT0), 0);
if (EpAvail.Word == 0)
{ // There is not enough buffer space in the endpoint for validating the final packet
// - ZLP will be handled on next Packet Transmitted interrupt
HISTO(DEFAULT_HISTORY, "NoAv", 0, 0, 0);
// Assert: We should only get here if the transfer size is an exact-packet multiple
ASSERT((ByteCount % Endpoint->Priv.EpMaxPkt.Word) == 0);
break;
}
#if NET2272_16BIT
// 16 Bit Mode
// - If the transfer size is an odd number of bytes, change the NET2272
// local bus width to 8 bit, write the last byte, then restore the
// local bus width to 16 bit
// Tip: If all USB IN transfers are guaranteed to be an even number of
// bytes (0, 2, 4, ...) then this section can be removed.
if (ByteCount & (1<<0))
{ // Transfer is an odd byte size (1, 3, 5, ...)
BYTE LocCtl = NETCHIP_READ(LOCCTL);
NETCHIP_WRITE(LOCCTL, LocCtl & ~(1<<DATA_WIDTH));
NETCHIP_BASEADDRESS[EP_DATA].NcReg = *(pTxBuf++);
NETCHIP_WRITE(LOCCTL, LocCtl);
}
#endif
#if _NCVIRTUALENDPOINTS
// ZLP and virtualization: Track ZLP in case the last one or two packets
// of the transfer must be virtualized.
// - If virtualized endpoints are not being applied, this section can be removed
if (Endpoint->Priv.LastPacketSize == Endpoint->Priv.EpMaxPkt.Word)
{ // The transfer includes a ZLP
// - If this transfer needs to be virtualized, the last packet is a ZLP
Endpoint->Priv.LastPacketSize = 0;
}
#endif // _NCVIRTUALENDPOINTS
// Post-validate partially-filled (or even empty) buffer:
// - Final bytes of the USB transfer have been written into the NET2272
// buffers. Validate the endpoint to allow the endpoint logic to send
// a short (or zero length) packet:
NETCHIP_WRITE(EP_TRANSFER0, 0);
}
// Change packet interrupt handler to handle the final packets being taken by the host
Endpoint->Priv.PioPacketHandler = TxFinalPio;
HISTO(DEFAULT_HISTORY, "TAll", Endpoint->Priv.pPkt - (PBYTE)Transfer->TransferBuffer, NETCHIP_READ(EP_STAT0), NETCHIP_READ(EP_STAT1));
NCDEBUG(NETCHIP_WRITE(EP_STAT1,
(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
0);)
break;
}
}
NC_LED2(FALSE); // Turn RDK daughter board LED OFF
// History Tip: If a client completion handler started a new transfer on this endpoint,
// this history entry reflects the new transfer, not the completed one!
HISTO(DEFAULT_HISTORY, ")TxP", Endpoint->Priv.pPkt - (PBYTE)Transfer->TransferBuffer, NETCHIP_READ(EP_STAT0), Endpoint->Priv.BytesRemaining);
}
///////////////////////////////////////////////////////////////////////////////
void
Dma_InterruptHandler(
void
)
{ // DMA controller's interrupt handler
NCPRINTF(VOLUME_MINIMUM, ("Dma_InterruptHandler(): DMA not implemented\n"));
NCFAULT();
}
///////////////////////////////////////////////////////////////////////////////
void
Nc_InterruptHandler(
void
)
{ // When the NET2272 asserts its INT# pin, the system interrupt controller
// quickly transfers control here...
// This section, and any function called from within it, is running in an interrupt context:
// - Many API functions are performance-tuned to run in an interrupt context. If
// the client chooses to call such a function outside of an interrupt context,
// an assert should be generated to serve as a warning. The developer may choose
// to protect the section (e.g. disable interrupts), or restructure to call
// the API from within a NetChip interrupt context.
// - For example, a client may wish to call the API Endpoint Halt routine from a
// non-interrupt context (or lower priority interrupt context); if a USB transfer
// interrupt occurs on the same endpoint while the CPU is still in the API halt
// routine, erroneous, unpredictable behavior is sure to occur.
NCBYTE PhysEp;
NCBYTE IrqStat0;
UINT EndpointActivity = 0;
PNC_ENDPOINT_OBJECT Endpoint;
// Use USB frame as a timing mechanism for preventing virtualization of recently
// un-virtualized endpoints
static BYTE OldFrame0;
BYTE NewFrame0 = NETCHIP_READ(FRAME0);
BOOL FramesSinceLastInterrupt = (OldFrame0 == NewFrame0)? FALSE: TRUE;
ASSERT(!NcDebug_InterruptContext);
NCDEBUG(NcDebug_InterruptContext = TRUE;)
NCPRINTF(VOLUME_MAXIMUM, ("Nc_InterruptHandler(). . .\n"));
HISTO(DEFAULT_HISTORY, "Int(", OldFrame0, NewFrame0, FramesSinceLastInterrupt);
OldFrame0 = NewFrame0;
// Handle physical data endpoint interrupts (one endpoint at a time, not including EP0)
for (PhysEp = FIRST_PHYSICAL_ENDPOINT; PhysEp < PHYSICAL_ENDPOINT_COUNT; PhysEp++)
{ // For all physical endpoints...
IrqStat0 = NETCHIP_READ(IRQSTAT0);
Endpoint = PhysicalEndpoints[PhysEp];
ASSERT(Endpoint != NULL);
HISTO(DEFAULT_HISTORY, "PhLp", NCHISTO_TRANSFER(Endpoint), 0, IrqStat0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -