📄 ncdevice.c
字号:
// Validate test packet
NETCHIP_WRITE(EP_TRANSFER0, 0);
}
}
///////////////////////////////////////////////////////////////////////////////
// Setup Request Packet support routines
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Control transfer support:
// - Setup packet phase
// - Data phase
// - Control Read (USB IN)
// - Control Write (USB OUT))
// - Status phase
// - See USB 2.0 8.5.3
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#define TIMEOUT_CATCHER TRUE // TRUE: Enable and show packet transfer timeouts
// The timeout catcher can expose marginal signal quality issues. If you experience
// lots of timeouts, you may need to investigate your USB signal quality:
// - Circuit board layout
// - Power and ground
// - Recommendation: Contact NetChip for layout assistance *before* building
// your first PCBs
///////////////////////////////////////////////////////////////////////////////
STATIC void
EpZero_RxPackets(
PNC_ENDPOINT_OBJECT Endpoint
)
{ // Receive packets on Endpoint Zero (Control Write data phase)
// - The host may start the status phase ANY TIME after any data phase OUT data packet
// - The status phase starts with IN tokens (See USB 8.5.3)
// - Status phase IN tokens cause endpoint zero to switch to an IN endpoint. Endpoint
// zero registers may therefore read back unexpected IN endpoint content
// - Because of the status phase switch, after the final byte of the Control Write
// is read from endpoint, registers should not be written or read (they may not
// act as expected!)
// NetChip Porting guide: Port this section 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.
#pragma message(_NC_MESSAGE"EpZero_RxPackets(): Control Write routine may not be needed")
// This routine may not be needed: Standard USB "Chapter 9" requests do not require
// Control Write with data phase support, nor do many class devices. If your device
// does not require Control Writes with a data phase this routine and its references,
// can probably be removed without consequence.
PNET2272_EP_DATA pRxBuf = (PNET2272_EP_DATA)Endpoint->Priv.pPkt;
NCBYTE EpStat0;
WORDBYTE EpAvail;
ASSERT(NETCHIP_READ(PAGESEL) == EP0);
HISTO(DEFAULT_HISTORY, "RxP(", 0, pRxBuf, Endpoint->Priv.BytesRemaining);
ASSERT(Endpoint->CompletionStatus == NCSTATUS_PENDING);
ASSERT(Endpoint->Transfer->TransferSize >= WLENGTH); // Client buffer must be large enough for host's transfer!
// Enable interrupts required for Endpoint Zero Rx transfer (disabling all others)
// - Other interrupt enables may have been set by standard transfer API routine, but
// they do not apply to this transfer
NETCHIP_WRITE(EP_IRQENB, (1<<DATA_PACKET_RECEIVED_INTERRUPT_ENABLE));
do
{
#if TIMEOUT_CATCHER && _NCDEBUG
if (NETCHIP_READ(EP_STAT1) & (1<<TIMEOUT))
{ // A USB timeout has occurred
NCPRINTF(VOLUME_LOW, ("RxPacketsPio(): Warning: Timeout detected on USB EP:%2.2x\n", Endpoint->Priv.PhysEp));
NETCHIP_WRITE(EP_STAT1, 1<<TIMEOUT);
}
#endif
EpAvail.Byte[MYEND_LO] = NETCHIP_READ(EP_AVAIL0);
EpAvail.Byte[MYEND_HI] = NETCHIP_READ(EP_AVAIL1);
ASSERT(EpAvail.Word <= Endpoint->Priv.EpMaxPkt.Word);
ASSERT(Endpoint->Priv.BytesRemaining >= EpAvail.Word);
if (EpAvail.Word == 0)
{ // No data available in endpoint buffer
HISTO(DEFAULT_HISTORY, "NoAv", 0, NETCHIP_READ(EP_STAT0), 0);
break;
}
// We are now committed to copying data from the endpoint
// - There is data in the endpoint to be transferred
// - There is space available in system memory to put that data
NC_LED1(TRUE); // Turn RDK daughter board LED ON
// Re-arm endpoint for another interrupt
NETCHIP_WRITE(EP_STAT0,
(1<<DATA_PACKET_RECEIVED_INTERRUPT) | // Required
(1<<DATA_OUT_TOKEN_INTERRUPT) | // Info only
0);
// Transfer accounting
Endpoint->Priv.pPkt += EpAvail.Word;
Endpoint->Priv.BytesRemaining -= EpAvail.Word;
HISTO(DEFAULT_HISTORY, "RxCp", EpAvail.Word, NETCHIP_READ(EP_STAT0), Endpoint->Priv.BytesRemaining);
ASSERT(Endpoint->Priv.BytesRemaining >= 0);
#if NET2272_16BIT
// Recalculate loop counter for 16 bit accesses
EpAvail.Word = (USHORT)((EpAvail.Word + 1)>>1);
#endif
// Copy bytes to memory from endpoint
// - For best performance, this loop should be optimized and written in assembler
ASSERT((EpAvail.Word == 0) || (pRxBuf != NULL));
while(EpAvail.Word--)
{
*(pRxBuf++) = NETCHIP_BASEADDRESS[EP_DATA].NcReg;
}
if (Endpoint->Priv.BytesRemaining == 0)
{ // Control Write is complete
// - Exit loop without reading or writing endpoint registers. If the status
// phase starts after the final byte of the packet is read from EP_DATA,
// the endpoint can switch from OUT to IN, possibly causing unexpected
// results for some register reads and writes. These registers and bits
// are known to cause problems:
// - EP_AVAIL
// - EP_TRANSFER
// - NAK OUT Packets
// - Buffer Empty
Endpoint->CompletionStatus = NCSTATUS_SUCCESS;
HISTO(DEFAULT_HISTORY, "BR=0", NETCHIP_READ(EP_CFG), NETCHIP_READ(EP_STAT0), 0);
break;
}
EpStat0 = NETCHIP_READ(EP_STAT0);
HISTO(VOLUME_MAXIMUM, "Loop", 0, EpStat0, Endpoint->Priv.BytesRemaining);
} while (!(EpStat0 & (1<<BUFFER_EMPTY)));
// Clear Endpoint Transfer registers:
// - These registers represent the number of bytes in the endpoint. However
// if these registers contain non-zero values on a subsequent Control Read,
// the endpoint will erroneously use the values as a pre-validation count.
// That is, for the next Control Read, the host may erroneously get the
// number of bytes specified by these Endpoint Transfer registers!)
// - The Endpoint Transfer registers *must* be cleared before the status phase
// can be allowed to start.
ASSERT(NETCHIP_READ(EP_RSPSET) & (1<<CONTROL_STATUS_PHASE_HANDSHAKE));
NETCHIP_WRITE(EP_TRANSFER2, 0);
NETCHIP_WRITE(EP_TRANSFER1, 0);
NETCHIP_WRITE(EP_TRANSFER0, 0);
NC_LED1(FALSE); // Turn RDK daughter board LED OFF
HISTO(DEFAULT_HISTORY, ")RxP", Endpoint->Priv.pPkt - (PBYTE)Endpoint->Transfer->TransferBuffer, NETCHIP_READ(EP_STAT0), Endpoint->Priv.BytesRemaining);
}
///////////////////////////////////////////////////////////////////////////////
STATIC void
EpZero_TxPackets(
PNC_ENDPOINT_OBJECT Endpoint
)
{ // Transmit packets on Endpoint Zero (Control Read data phase)
// - The host may start the status phase ANY TIME after reading a data phase packet
// - A Control Read status phase starts with an OUT token (See USB 8.5.3)
// - Status phase OUT tokens cause Endpoint Zero to switch to an OUT endpoint. Endpoint
// zero registers may therefore read back unexpected OUT endpoint content!
// - Because of the status phase switch, after the final byte of the Control Read
// is written to the endpoint (or validated, if not a Max Packet Multiple) endpoint
// registers should not be written or read (they may read confounding values!)
// NetChip Porting guide: Port this section carefully. It should be ported without
// adding 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.
PNET2272_EP_DATA pTxBuf = (PNET2272_EP_DATA)Endpoint->Priv.pPkt;
NCDEBUG(PNC_TRANSFER_OBJECT Transfer = Endpoint->Transfer;)
HISTO(DEFAULT_HISTORY, "TxP(", 0, pTxBuf, Endpoint->Priv.BytesRemaining);
ASSERT(NETCHIP_READ(PAGESEL) == EP0);
ASSERT(Endpoint->CompletionStatus == NCSTATUS_PENDING);
ASSERT((ULONG)(
(NETCHIP_READ(EP_TRANSFER0)<<0) +
(NETCHIP_READ(EP_TRANSFER1)<<8) +
(NETCHIP_READ(EP_TRANSFER2)<<16)) > Endpoint->Priv.BytesRemaining);
// Enable interrupts required for Endpoint Zero Tx transfer (disabling all others)
// - Other interrupt enables may have been set by standard transfer API routine, but
// they do not apply to this transfer
NETCHIP_WRITE(EP_IRQENB, (1<<DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE));
for (;;)
{ // Continue loading the endpoint until:
// - The final packet gets loaded into the endpoint
// - The endpoint has no available space
NCBYTE EpStat0;
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, ("EpZero_TxPackets(): Warning: Timeout detected on USB EP:%2.2x\n", Endpoint->Priv.PhysEp));
NETCHIP_WRITE(EP_STAT1, 1<<TIMEOUT);
}
#endif
// Arm endpoint for Data Packet Transmitted Interrupt
NETCHIP_WRITE(EP_STAT0, (
(1<<DATA_PACKET_TRANSMITTED_INTERRUPT) | // Required
(1<<DATA_IN_TOKEN_INTERRUPT) | // Info only
0));
EpStat0 = NETCHIP_READ(EP_STAT0);
if (!(EpStat0 & (1<<BUFFER_EMPTY)))
{ // Buffer not empty
// - There is no room in the endpoint for more data
// - We'll have to leave and wait for a packet to be taken (Data Packet
// Transmitted Interrupt) before we can load more data into the endpoint
HISTO(DEFAULT_HISTORY, "!Emt", EpStat0, NETCHIP_READ(EP_STAT0), 0);
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
LoopCount = ByteCount = min(Endpoint->Priv.EpMaxPkt.Word, Endpoint->Priv.BytesRemaining);
// Transfer accounting
Endpoint->Priv.BytesRemaining -= ByteCount;
Endpoint->Priv.pPkt += ByteCount;
HISTO(DEFAULT_HISTORY, "TxCp", ByteCount, EpStat0, 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 for 16 bit mode below...
LoopCount >>= 1;
#endif
// Copy bytes to endpoint
// - For best performance, this loop should be optimized, and written in assembler
ASSERT((LoopCount == 0) || (pTxBuf != NULL));
while (LoopCount--)
{
NETCHIP_BASEADDRESS[EP_DATA].NcReg = *(pTxBuf++);
}
if (Endpoint->Priv.BytesRemaining == 0)
{ // No more bytes in this transfer
// - Handle Short Packet validation
#if NET2272_16BIT
// NET2272 is being used in 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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -