📄 ncfwapi.c
字号:
// Transfer accounting
Endpoint->Priv.BytesRemaining -= EpAvail.Word;
Endpoint->Priv.pPkt += EpAvail.Word;
HISTO(DEFAULT_HISTORY, "RxCp", EpAvail.Word, EpStat0, Endpoint->Priv.BytesRemaining);
#if NET2272_16BIT
// Recalculate loop counter for 16 bit accesses
EpAvail.Word = (USHORT)((EpAvail.Word + 1)>>1);
#endif
#pragma message(_NC_MESSAGE"Recommendation: Optimize Rx copy loop in assembler")
// Copy bytes (or words) to memory from endpoint
// - For best performance, this loop should be optimized and written in assembler
while (EpAvail.Word--)
{
*(pRxBuf++) = NETCHIP_BASEADDRESS[EP_DATA].NcReg;
}
// After we read the final byte from an endpoint buffer, the endpoint's alternate buffer
// may become visible to us. It will become visible if and only if the USB host successfully
// transferred a packet to it. When it becomes visible, the following are updated:
// - EP_STAT0
// - EP_STAT1
// - EP_AVAIL0, EP_AVAIL1
EpStat0 = NETCHIP_READ(EP_STAT0);
if (EpStat0 & (1<<SHORT_PACKET_TRANSFERRED_INTERRUPT))
{ // Eliminate timing exposure: NET2272 OUT endpoint logic sets Short Packet
// status slightly before (i.e. one or two nSecs before) Buffer Empty
// status becomes valid:
// - Re-reading EP_STAT0 ensures Buffer Empty is accurate
EpStat0 = NETCHIP_READ(EP_STAT0);
}
HISTO(VOLUME_MAXIMUM, "Loop", 0, EpStat0, Endpoint->Priv.BytesRemaining);
} while (!(EpStat0 & (1<<BUFFER_EMPTY)));
if (EpStat0 & (1<<SHORT_PACKET_TRANSFERRED_INTERRUPT))
{ // A USB short packet has been received, terminating this USB transfer
// - All bytes of the transfer have been successfully read from the endpoint and
// written to system memory
// - Number of bytes transferred may be LESS than requested (but must NEVER EXCEED request!)
// - Endpoint will NAK subsequent host requests
NETCHIP_DATA_TYPE dummy;
// Force "end of transfer" handling
Endpoint->Priv.BytesRemaining = 0;
Endpoint->CompletionStatus = NCSTATUS_SUCCESS;
NC_VIRT_EP(Endpoint->Priv.SwapCandidate = SwapCandidate_Instant;)
// Handle possibility of a Zero-Length OUT packet
// - NET2272 OUT endpoints use the final read from Endpoint Data to signal that
// the endpoint's buffer has been handled by firmware. Zero length OUT packets
// have no data, but endpoint logic still requires a read from EP_DATA
// - Reading EP_DATA before clearing NAK OUT Packets reliably and safely addresses
// the issue, and has no side-effects.
dummy.NcReg = NETCHIP_BASEADDRESS[EP_DATA].NcReg;
HISTO(DEFAULT_HISTORY, "ShPk", EpStat0, NETCHIP_READ(EP_STAT0), 0);
#if _NCVIRTUALENDPOINTS
NETCHIP_WRITE(EP_STAT0,
(1<<DATA_PACKET_RECEIVED_INTERRUPT) | // Required
(1<<DATA_OUT_TOKEN_INTERRUPT) | // Required (for Token Notification)
(1<<SHORT_PACKET_TRANSFERRED_INTERRUPT) | // Required (Prepare for end of new OUT transfer)
0);
// Assert: NAK OUT Packets has automatically been set by the endpoint ensuring that this endpoint
// is now blocking (NAK'ing) any host requests. The endpoint's condition is therefore
// quiescent, and will not change (until another transfer is started)
ASSERT(EpStat0 & NETCHIP_READ(EP_STAT0) & (1<<NAK_OUT_PACKETS));
#else
NETCHIP_WRITE(EP_STAT0,
(1<<DATA_PACKET_RECEIVED_INTERRUPT) | // Required
(1<<DATA_OUT_TOKEN_INTERRUPT) | // Required (for Token Notification)
(1<<SHORT_PACKET_TRANSFERRED_INTERRUPT) | // Required (Prepare for end of new OUT transfer)
(1<<NAK_OUT_PACKETS) | // Required (Endpoint can accept packets immediately)
0);
#endif
}
if (Endpoint->Priv.BytesRemaining == 0)
{ // Zero bytes remain in the transfer, however the transfer may not be *quite* complete:
// - Corner case: If the client requested that exact packet multiple transfers are
// to be terminated (i.e. "Apply ZLP", then another packet (usually, but not
// necessarily, a Zero Length OUT packet) must be received and accounted for:
if (
(Endpoint->CompletionStatus == NCSTATUS_PENDING) && // Transfer not yet completed (no short packet, no error)?
(!(Transfer->TransferFlags & (1<<NC_TRANSFER_FLAG_APPLY_ZLP))) // Client does NOT require ZLP to terminate exact packet multiples?
)
{ // Force transfer to complete successfully (without a short packet)
// - Zero bytes remain, and client does not expect another packet to terminate the transfer
// Assert: To get here, the transfer MUST have resulted in an exact packet multiple (or
// the Short Packet Transferred section would have completed the transfer!)
Endpoint->CompletionStatus = NCSTATUS_SUCCESS;
NC_VIRT_EP(Endpoint->Priv.SwapCandidate = SwapCandidate_TransferComplete;)
//XXXXXXXXXXXX Virtualization exposure (Rare): The endpoint can still accept packets, but
//XXXXXXXXXXXX there's no Transfer! Perhaps... Virtualize the EP (or just set NAK OUT Packets?); if packets happened to
//XXXXXXXXXXXX arrive before virtualization, return a code and set EP to locked (permanently?);
//XXXXXXXXXXXX otherwise, Success..? (Client completion should start another transfer if not Success.)
}
if (Endpoint->CompletionStatus != NCSTATUS_PENDING)
{ // Transfer has completed
// - Completion may be due to success or error
// - Clean up and call client completion handler
//
// Virtulized endpoints: Record current state of NAK OUT Packets
// - Next transfer must be careful to clear NAK OUT Packets safely! (It
// is unsafe for the next transfer to clear NAK OUT Packets if the
// endpoint is not specifically NAK'ing packets)
// - For convenience, use EP_RSP
NC_VIRT_EP(Endpoint->Priv.EpRsp = NETCHIP_READ(EP_RSPSET);)
BufferTooSmall:
NETCHIP_WRITE(EP_IRQENB, 0);
Endpoint->BytesTransferred = Endpoint->Priv.pPkt - (PBYTE)Transfer->TransferBuffer;
NC_STATISTIC(Endpoint->Priv.TotalBytesTransferred += Endpoint->BytesTransferred;)
NC_STATISTIC(Endpoint->Priv.TotalTransfers++;)
HISTO(DEFAULT_HISTORY, "RCmp", Endpoint->BytesTransferred, EpStat0, 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);)
// Call client completion routine
// - Client should return from this call as quickly as possible
// - Client may start another transfer on this or another endpoint
Transfer->ClientCompletionHandler(Endpoint);
}
}
else
{ // Transfer has not completed
Endpoint->BytesTransferred = Endpoint->Priv.pPkt - (PBYTE)Transfer->TransferBuffer;
HISTO(DEFAULT_HISTORY, "RPrt", Endpoint->BytesTransferred, EpStat0, 0);
Transfer->PartialTransferHandler(Endpoint);
}
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, ")RxP", Endpoint->Priv.pPkt - (PBYTE)Transfer->TransferBuffer, EpStat0, Endpoint->Priv.BytesRemaining);
}
///////////////////////////////////////////////////////////////////////////////
void
TxPacketsPio(
PNC_ENDPOINT_OBJECT Endpoint
);
///////////////////////////////////////////////////////////////////////////////
void
TxFinalPio(
PNC_ENDPOINT_OBJECT Endpoint
)
{ // Handle final packets of USB IN (Tx) transfer
// - The final packets of the transfer were written to the endpoint
// - Now handle the host actually taking those packets
// - Tip: There is a small possibility that a corrupted ACK handshake could
// prevent firmware from immediately recognizing that the final Tx packet
// has been taken by the host. See USB 2.0: 8.6.4
PNC_TRANSFER_OBJECT Transfer = Endpoint->Transfer;
BYTE EpBuffStates;
ASSERT(Endpoint->Priv.PhysEp != EP0);
NETCHIP_WRITE(PAGESEL, Endpoint->Priv.PhysEp);
// Arm endpoint for Data Packet Transmitted Interrupt
NETCHIP_WRITE(EP_STAT0,
(1<<DATA_PACKET_TRANSMITTED_INTERRUPT) | // Required
(1<<DATA_IN_TOKEN_INTERRUPT) | // Required (for Token Notification)
0);
EpBuffStates = NETCHIP_READ(EP_BUFF_STATES);
HISTO(DEFAULT_HISTORY, "TFin", NCHISTO_TRANSFER(Endpoint), EpBuffStates, NETCHIP_READ(EP_STAT0));
switch(EpBuffStates)
{
case BUFF_FREE<<BUFFER_A_STATE | BUFF_LCL<<BUFFER_B_STATE:
case BUFF_FREE<<BUFFER_B_STATE | BUFF_LCL<<BUFFER_A_STATE:
// USB host has taken the final IN packets of the transfer
// - This transfer is really really done
NETCHIP_WRITE(EP_IRQENB, 0);
Endpoint->BytesTransferred = Endpoint->Priv.pPkt - (PBYTE)Transfer->TransferBuffer;
NC_STATISTIC(Endpoint->Priv.TotalBytesTransferred += Endpoint->BytesTransferred;)
NC_STATISTIC(Endpoint->Priv.TotalTransfers++;)
Endpoint->CompletionStatus = NCSTATUS_SUCCESS;
NC_VIRT_EP(Endpoint->Priv.SwapCandidate = SwapCandidate_Instant;)
HISTO(DEFAULT_HISTORY, "TCmp", NCHISTO_TRANSFER(Endpoint), NETCHIP_READ(EP_STAT0), Endpoint->BytesTransferred);
// Restore normal Tx packet handler
// - CRITICAL NOTE: The value in PIO Packet Handler is used as a
// flag by the Reassign Best routine to indicate that the final
// packets *may* need to be handled. Now that the final packets *have*
// been handled, we clear the flag by reverting back to the normal Tx
// packet handler:
Endpoint->Priv.PioPacketHandler = TxPacketsPio;
// Call client's transfer completion handler
// - Client should return from this call as quickly as possible
// - Client's completion routine may start another transfer on this
// endpoint. If that happens, packets will get preloaded into the
// endpoint. Virtualization must be considered (i.e. its possible
// that we are completing a transfer on an endpoint that has been
// virtualized.)
Transfer->ClientCompletionHandler(Endpoint);
break;
default:
// Final packet has not been taken by the host
NC_VIRT_EP(Endpoint->Priv.SwapCandidate = SwapCandidate_SomeBytesTransferred;)
break;
}
}
///////////////////////////////////////////////////////////////////////////////
void
TxPacketsPio(
PNC_ENDPOINT_OBJECT Endpoint
)
{ // Transmit packets (USB IN) using programmed I/O method
// - Fill endpoint with as many USB packets as possible until:
// - No more endpoint buffers available (endpoint buffers full)
// - Client request fulfilled (all requested bytes transferred)
// - This method cannot be applied to Endpoint Zero Transfers (i.e Control Reads)
// NetChip Porting guide: Port this section very carefully. It should be ported
// without functional changes. It has been carefully designed and fully tested
// to ensure safe and reliable operation over a wide variety of conditions. If
// you experience problems with this section, please contact NetChip.
PNC_TRANSFER_OBJECT Transfer = Endpoint->Transfer;
PNET2272_EP_DATA pTxBuf = (PNET2272_EP_DATA)Endpoint->Priv.pPkt;
ASSERT(Transfer != NULL);
ASSERT(Endpoint->Priv.PhysEp != EP0);
NC_VIRT_EP(ASSERT(!Endpoint->Priv.Virtualized);)
NETCHIP_WRITE(PAGESEL, Endpoint->Priv.PhysEp);
HISTO(DEFAULT_HISTORY, "TxP(", NCHISTO_TRANSFER(Endpoint), pTxBuf, Endpoint->Priv.BytesRemaining);
ASSERT(Endpoint->CompletionStatus == NCSTATUS_PENDING);
ASSERT(NETCHIP_READ(EP_CFG) & (1<<ENDPOINT_DIRECTION));
// Enable only Data Packet Transmitted interrupt (disabling Data IN Token Interrupt)
// - Data IN Token Interrupt Enable is set by API to interrupt on the host's
// request to *start* a transfer). For the rest of the transfer, interrupt
// on Data Packet Transmitted:
NETCHIP_WRITE(EP_IRQENB, (1<<DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE));
NC_VIRT_EP(Endpoint->Priv.SwapCandidate = SwapCandidate_SomeBytesTransferred;)
for (;;)
{ // Continue loading the endpoint until:
// - The final packet gets loaded into the endpoint
// - The endpoint has no available space
NCBYTE EpStat0;
WORDBYTE EpAvail;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -