📄 ncdevice.c
字号:
NETCHIP_BASEADDRESS[EP_DATA].NcReg = *(pTxBuf++);
NETCHIP_WRITE(LOCCTL, LocCtl);
}
#endif
// 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
// - ZLP tip: If the transfer is an exact packet multiple, firmware adds
// a ZLP. If the host does not take the ZLP (e.g. wLength is an exact
// packet multiple, AND the device is to return exactly wLength bytes)
// the extraneous ZLP gets discarded by endpoint logic on the next Setup Request.
NETCHIP_WRITE(EP_TRANSFER2, 0);
NETCHIP_WRITE(EP_TRANSFER1, 0);
NETCHIP_WRITE(EP_TRANSFER0, 0);
// Data phase transfer completed successfully
Endpoint->CompletionStatus = NCSTATUS_SUCCESS;
HISTO(DEFAULT_HISTORY, "TCmp", NETCHIP_READ(EP_CFG), NETCHIP_READ(EP_STAT0), 0);
break;
}
}
NC_LED2(FALSE); // Turn RDK daughter board LED OFF
HISTO(DEFAULT_HISTORY, ")TxP", Endpoint->Priv.pPkt - (PBYTE)Endpoint->Transfer->TransferBuffer, NETCHIP_READ(EP_STAT0), Endpoint->Priv.BytesRemaining);
}
///////////////////////////////////////////////////////////////////////////////
STATIC void
EpZero_StatusPhase(
PNC_ENDPOINT_OBJECT Endpoint
)
{ // Status phase is the last phase of a Control Transfer (See USB 2.0 8.5.3)
// - Allow the status phase to complete
// - Lowest priority: Setup and data phase handlers must complete before this section runs!
PNC_TRANSFER_OBJECT Transfer = Endpoint->Transfer;
NETCHIP_WRITE(PAGESEL, EP0);
HISTO(DEFAULT_HISTORY, "StPh", NETCHIP_READ(EP_CFG), NETCHIP_READ(EP_STAT0), NETCHIP_READ(IRQSTAT1));
// Allow the status phase of the control transfer to complete
// - Control Status Phase Handshake was set by the chip when the setup packet
// arrived. While set, the chip automatically NAKs the host's Status Phase tokens.
// - Once Control Status Phase Handshake is cleared, the host and NET2272
// will quickly handshake to complete the status phase
// - Tip: Endpoint Zero changes its direction to match the Status Phase
// as soon as the host *starts* issuing Status Phase tokens! After a data
// phase completes, firmware must be careful with endpoint registers, as
// the endpoint direction could change at any time!
NETCHIP_WRITE(EP_RSPCLR, 1<<CONTROL_STATUS_PHASE_HANDSHAKE);
// Prevent Control Status Interrupt (Status Phase) from interrupting again:
// - On the next Setup Request (Setup Phase) interrupt, firmware should clear
// Control Status Interrupt and enable its interrupt
NETCHIP_WRITE(IRQENB1, NETCHIP_READ(IRQENB1) & ~(1<<CONTROL_STATUS_INTERRUPT_ENABLE));
if (WLENGTH != 0)
{ // Host's request included a data phase
// - Client should have started a data phase (in its setup request handler)
// - Data phase may (or may not!) have completed
// - Clean up and call client completion handler
NETCHIP_WRITE(EP_IRQENB, 0);
Endpoint->BytesTransferred = Endpoint->Priv.pPkt - (PBYTE)Transfer->TransferBuffer;
NC_STATISTIC(LogicalEndpoints[0].Priv.TotalBytesTransferred += Endpoint->BytesTransferred;)
NC_STATISTIC(LogicalEndpoints[0].Priv.TotalTransfers++;)
_NC_DISPLAY_MEMORY(VOLUME_MAXIMUM, Endpoint->Transfer->TransferBuffer, Endpoint->BytesTransferred, WORDSIZE_BYTE);
if (Endpoint->CompletionStatus == NCSTATUS_PENDING)
{ // A data phase transfer was started, but the host ended the data phase
// before the data phase could complete
// - Data phase has not completed normally. Post error code for client
NCPRINTF(VOLUME_MINIMUM, ("EpZero_StatusPhase(): Completing Data Phase early!\n"));
HISTO(DEFAULT_HISTORY, "StE!", NETCHIP_READ(EP_CFG), NETCHIP_READ(EP_STAT0), NETCHIP_READ(IRQSTAT1));
Endpoint->CompletionStatus = NCSTATUS_UNSUCCESSFUL;
}
// Call client's transfer completion handler
// - Client should return from this call as quickly as possible
ASSERT(Transfer->ClientCompletionHandler != NULL);
Transfer->ClientCompletionHandler(Endpoint);
}
//Assert: There should not be any Endpoint Zero transfers pending:
// - Client must NOT start an Endpont Zero transfer from its completion handler. Client
// can only start an Endpoint Zero transfer from its Device Request Handler
ASSERT(Endpoint->CompletionStatus != NCSTATUS_PENDING);
// Restore client's transfer object
Endpoint->Transfer = ClientTransferZero;
}
///////////////////////////////////////////////////////////////////////////////
STATIC void
EpZero_DataPhase(
PNC_ENDPOINT_OBJECT Endpoint
)
{ // Start or continue the data phase (Control Read or Write) of a control transfer
// - If data phase completes (or there is no data phase) allow the status phase
// to complete
// - See USB 2.0: 8.5.3
// Tips and considerations: Control transfers have subtle issues. NetChip firmware
// is carefully crafted to ensure that these issues won't create problems regardless
// of the platform the code is ported to. However a few of the issues are discussed
// here for those wishing to investigate NetChip methods:
// - The host may move to the Status Stage early, terminating a control transfer
// before all bytes of the data phase have been transferred. Firmware must
// be able to recognize this situation respond correctly, predictably and reliably.
// - Firmware must be immune to sudden changes in Endpoint Direction. When the host
// moves to the Status Stage, the NET2272 will soon switch its direction to match. For
// instance, if the Data Stage is OUT (Control Write) the host will likely
// issue Status Stage IN tokens soon after the final data phase OUT packet
// is ACK'd. When firmware eventually reads the final data phase byte from the
// endpoint, the endpoint logic will switch from being an OUT endpoint to IN
// endpoint. At that moment, various Endpoint Zero registers will switch as appropriate
// for an IN endpoint; firmware must act correctly, predictably and reliably.
// - Hide Status Phase OFF: 'Stale' Packet Received and Packet Transmitted
// bits may be left over from the status phase of a previous control transfer. These
// stale bits must not cause problems. Consider, for instance, a Control Read
// followed closely by a Control Write: The status phase of the Control Read
// will set Packet Received; the data phase of the Control Write will *also* set
// Packet Received! It may be difficult for firmware to distinguish the
// difference. If Hide Status Phase is OFF, control transfer firmware must
// robustly handle such possibilities.
NCDEBUG(PNC_TRANSFER_OBJECT Transfer = Endpoint->Transfer;)
NETCHIP_WRITE(PAGESEL, EP0);
HISTO(DEFAULT_HISTORY, "DaPh", BMREQUESTTYPE, NETCHIP_READ(EP_STAT0), WLENGTH);
if (Endpoint->CompletionStatus == NCSTATUS_PENDING)
{ // Control transfer includes an uncompleted data phase
// - Transfer as much data-phase data as possible now
if (BMREQUESTTYPE & DEVICE_TO_HOST)
{ // Control Read (USB IN)
// - Assert: Transfer size restriction: The client's transfer must be
// no larger than the host's requested size:
ASSERT(Endpoint->Priv.BytesRemaining <= WLENGTH);
EpZero_TxPackets(Endpoint);
}
else if (WLENGTH != 0)
{ // Control Write (USB OUT), with some number of bytes
// Assert: Transfer size restriction:
// - The client must provide at least enough room for the
// host's requested size, but also, the client should not
// specify a transfer size larger than the host's request
// - Problems with endpoint switching (Endpoint Zero switching
// to an IN endpoint on status phase) can otherwise arise
ASSERT(WLENGTH == Transfer->TransferSize);
EpZero_RxPackets(Endpoint);
}
else
{ // Zero-length Control Write
// - No data to transfer!
Endpoint->CompletionStatus = NCSTATUS_SUCCESS;
}
}
if (Endpoint->CompletionStatus != NCSTATUS_PENDING)
{ // Either the data phase completed normally (all requested bytes transferred) or
// the request did not include a data phase (wLength is zero). Either way:
// - Data phase is complete
// - Status phase may now be allowed to complete (even if the host has not
// specifically started its Status Phase)
NETCHIP_WRITE(EP_IRQENB, 0);
EpZero_StatusPhase(Endpoint);
}
}
#if _NCDEBUG
///////////////////////////////////////////////////////////////////////////////
// Debugging support for printing host's eight-byte setup requests:
// - Special printf() formatting to add volume controls to setup packets
char SetupPacket_Msg[256]; // Show setup packet message (During debug)
UINT SetupPacket_PrintVolume; //
#define SetupPacket_LengthFormat "%-32s Len:%4.4x"
#endif
///////////////////////////////////////////////////////////////////////////////
STATIC void
StandardUsbRequestHandler(
PNCSTATUS NcStatus
)
{ // Parse standard USB setup requests:
// - If the request is not handled, return status is marked Unsuccessful. Otherwise,
// the status is not changed (this makes parsing a little more efficient)
// - Parser references a *copy* of Setup Packet read from NET2272. (Firmware
// must not reference the setup packet in the NET2272 because the host may
// issue a new setup request at any time!)
// - USB lists standard requests (See USB Spec: 9.4)
static WORDBYTE lewStatus; // Return status - used as a Little Endian Word
UINT Length;
PNC_ENDPOINT_OBJECT Endpoint;
lewStatus.Word = 0x0000; // Assume return value is 'success'
NETCHIP_WRITE(PAGESEL, EP0);
switch (BMREQUESTTYPE)
{ // This is a reasonably complete skeleton for handling standard USB setup requests:
// - Successful requests should 'return'
// - Failed or unhandled requests should 'break' causing endpoint zero to STALL
case HOST_TO_DEVICE | STANDARD | RECIPIENT_DEVICE:
switch (BREQUEST)
{
case CLEAR_FEATURE:
// Clear DEVICE Feature
if (WVALUE == DEVICE_REMOTE_WAKEUP)
{ // Disable our ability to wake a suspended host
PrivDeviceObject->HostWakeupEnable = FALSE;
NCDEBUG(sprintf(SetupPacket_Msg, "CLEAR_FEATURE, DEVICE_REMOTE_WAKEUP");)
return;
}
break;
case SET_FEATURE:
// Set DEVICE Feature
switch(WVALUE)
{
case DEVICE_REMOTE_WAKEUP:
// Enable our ability to wake a suspended host
PrivDeviceObject->HostWakeupEnable = TRUE;
NCDEBUG(sprintf(SetupPacket_Msg, "SET_FEATURE, DEVICE_REMOTE_WAKEUP");)
// Assert: A device that does not report Remote Wakeup capability in its
// configuration cannot have have its wakeup capability enabled!
ASSERT(UsbConfiguration->bmAttributes & (1<<5));
return;
case TEST_MODE:
// See USB 2.0: 7.1.20 and 9.4.9
// - USB 2.0: 7.1.20: "The transition to test mode must complete no later than 3ms after
// the completion of the status stage of the request." In other words, we don't have
// time to print messages before starting a test mode
switch(WINDEX_HI)
{
case USB_TEST_J:
case USB_TEST_K:
case USB_TEST_SE0_NAK:
case USB_TEST_FORCE_ENABLE:
case USB_TEST_PACKET:
NCDEBUG(SetupPacket_PrintVolume = VOLUME_LOW;)
NCDEBUG(sprintf(SetupPacket_Msg, "SET_FEATURE, TEST_MODE (Mode:0x%2.2x)", WINDEX_HI);)
NcDev_TestMode(WINDEX_HI);
return;
default:
break;
}
break;
default:
break;
}
break;
case SET_ADDRESS:
// NOTE: USB address changes *after* successful status stage (See USB 1.1: 9.4.6)
// - The NET2272 automatically changes the address after status stage
// - The address we write now will not updated until *after* the status phase
// - USB 2.0: 9.2.6.3: Within 2ms after the status stage of Set Address, the device
// must be able to accept packets at the new address. (This can be a gotcha!)
NETCHIP_WRITE(OURADDR, WVALUE_LO);
NCDEBUG(SetupPacket_PrintVolume = VOLUME_LOW;)
NCDEBUG(sprintf(SetupPacket_Msg, "Setting OURADDR:%2.2x", WVALUE_LO);)
return;
case SET_CONFIGURATION:
// Set Configuration:
// - Count and initialize endpoints in the configuration
NcApi_SetConfiguration(PrivDeviceObject);
// Notify client of Set Configuration event:
// - Tip: Most USB devices support configurations zero (de-configured) and
// one (configured). Hosts rarely (except for compliance testing!) issue
// a Set Configuration for configuration zero
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -