📄 ncfwapi.c
字号:
// This function malloc's memory for the USD:
// - BE SURE to free memory allocated by this function (use free())!
// - (The return pointer can be passed directly to free())
UINT AsciiLen;
PUSB_STRING_DESCRIPTOR Usd;
PBYTE UsdText;
UINT ii;
if (AsciiStr == NULL)
{ // No string to build!
return NULL;
}
AsciiLen = strlen(AsciiStr);
// Assert: Make sure string descriptor element sizes matches USB 2.0: 9.6.7
ASSERT((sizeof(USB_STRING_DESCRIPTOR) == 2) && (sizeof(USHORT) == 2));
// Determine length of USD (header plus wide string)
ii = sizeof(USB_STRING_DESCRIPTOR) + (AsciiLen*sizeof(USHORT));
// Get storage for USD (header plus string storage)
Usd = (PUSB_STRING_DESCRIPTOR)MALLOC(ii);
ASSERT(Usd);
// Set USD header
Usd->bLength = (BYTE)ii; // USD length
Usd->bDescriptorType = STRING_DESC; // USD type
// Fill in wide string
UsdText = (PBYTE)Usd + sizeof(USB_STRING_DESCRIPTOR); // Point to first byte of text in USD
for (ii = 0; ii < AsciiLen; ii++)
{ // Fill in USB descriptor string
*(UsdText++) = *(AsciiStr++);
*(UsdText++) = 0;
}
return Usd;
}
///////////////////////////////////////////////////////////////////////////////
BOOL
FindDescriptor(
PUSB_COMMON_DESCRIPTOR * pDescriptor,
NCBYTE DescriptorType,
PUSB_COMMON_DESCRIPTOR EndOfConfiguration
)
{ // Search a configuration (starting at pDescriptor) for descriptor
// matching the specified Descriptor Type
// - If successful, this function returns TRUE and the caller's Descriptor
// reference refers to the matching descriptor
// - Returns FALSE if a matching descriptor type is not found
// - This function is expected to be called reiteratively. Since the first
// call is expected to be a Configuration (which is unlikely to be the
// caller's requested descriptor type) the caller's work is simplified
// by always skipping the first descriptor. That way, the caller can
// simply call this function repeatedly (to find the next matching
// descriptor) without having to manually advance to the next descriptor.
ASSERT(EndOfConfiguration > *pDescriptor);
for (;;)
{
// Current descriptor bLength cannot be zero
// - If bLength is zero, this loop will hang forever!
ASSERT((*pDescriptor)->bLength != 0);
// Get next descriptor
*pDescriptor = (PUSB_COMMON_DESCRIPTOR)NEXT_USB_DESCRIPTOR(*pDescriptor);
if (*pDescriptor >= EndOfConfiguration)
{ // End of configuration: Did not find a match for requested Descriptor Type
return FALSE;
}
if ((*pDescriptor)->bDescriptorType == DescriptorType)
{ // Found descriptor matching caller's requested Descriptor Type
return TRUE;
}
}
}
///////////////////////////////////////////////////////////////////////////////
PNC_ENDPOINT_OBJECT
NcApi_FindUsbEp(
NCBYTE UsbEp
)
{ // Find a Endpoint Object matching the given USB endpoint
// - Return NULL if not found
NCBYTE LogicalEp;
HISTO(DEFAULT_HISTORY, "Fnd<", UsbEp, 0, 0);
if (UsbEp == EP0)
{ // Endpoint zero
return &LogicalEndpoints[EP0];
}
for (LogicalEp = 1; LogicalEp <= PrivDeviceObject->ConfigurationEndpointCount; LogicalEp++)
{ // For all logical endpoints in the configuration...
// - Find an endpoint that matches the requested physical endpoint
PNC_ENDPOINT_OBJECT Endpoint = &LogicalEndpoints[LogicalEp];
if (Endpoint->EpDescriptor->bEndpointAddress == UsbEp)
{ // Found match for caller's USB EP
HISTO(DEFAULT_HISTORY, ">Fnd", NCHISTO_TRANSFER(Endpoint), 0, 0);
return Endpoint;
}
}
// No endpoint matching caller's USB endpoint found!
HISTO(DEFAULT_HISTORY, "!Fnd", 0, 0, 0);
return NULL;
}
///////////////////////////////////////////////////////////////////////////////
#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
// - Contact NetChip support for help
///////////////////////////////////////////////////////////////////////////////
void
RxPacketsPio(
PNC_ENDPOINT_OBJECT Endpoint
)
{ // Receive packets (USB OUT) using programmed I/O method
// - Transfer as many USB packets to memory as possible until:
// - USB short packet received (terminates USB transfer)
// - No more USB packets available (endpoint buffer empty)
// - Client request fulfilled (all requested bytes transferred)
// - Usually called in an interrupt context when an endpoint's Data Packet
// Received Interrupt is TRUE.
// - This method cannot be applied to Endpoint Zero Transfers (i.e Control Writes)
// 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.
BYTE EpStat0;
WORDBYTE EpAvail;
PNET2272_EP_DATA pRxBuf = (PNET2272_EP_DATA)Endpoint->Priv.pPkt;
PNC_TRANSFER_OBJECT Transfer = Endpoint->Transfer;
ASSERT(Transfer != NULL);
ASSERT(Endpoint->Priv.PhysEp != EP0);
NETCHIP_WRITE(PAGESEL, Endpoint->Priv.PhysEp);
HISTO(DEFAULT_HISTORY, "RxP(", NCHISTO_TRANSFER(Endpoint), pRxBuf, Endpoint->Priv.BytesRemaining);
ASSERT(Endpoint->CompletionStatus == NCSTATUS_PENDING);
// Virtualized endpoints: Assume some packets will be transferred
NC_VIRT_EP(Endpoint->Priv.SwapCandidate = SwapCandidate_SomeBytesTransferred;)
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
EpStat0 = NETCHIP_READ(EP_STAT0);
EpAvail.Byte[MYEND_LO] = NETCHIP_READ(EP_AVAIL0);
EpAvail.Byte[MYEND_HI] = NETCHIP_READ(EP_AVAIL1);
ASSERT(EpAvail.Word <= Endpoint->Priv.EpMaxPkt.Word);
if (Transfer->TransferFlags & (1<<NC_TRANSFER_FLAG_TOKEN_NOTIFICATION))
{ // Client requesting notification of OUT token
// - OUT token (plus at least one packet) has been received
// - Complete transfer now, carefully leaving data and status in the chip's endpoint
// - Report number of bytes currently in the buffer via Bytes Transferred (even
// though *zero* bytes have actually been transferred.)
NETCHIP_WRITE(EP_IRQENB, 0);
Endpoint->BytesTransferred = EpAvail.Word;
Endpoint->CompletionStatus = NCSTATUS_SUCCESS;
HISTO(DEFAULT_HISTORY, "OTok", NCHISTO_TRANSFER(Endpoint), EpStat0, Endpoint->BytesTransferred);
// Call client completion routine
// - Client should return from this call as quickly as possible
// - Client may start another transfer on this or another endpoint
NETCHIP_WRITE(EP_STAT0, 1<<DATA_OUT_TOKEN_INTERRUPT); // Required for next Token Notification
Transfer->ClientCompletionHandler(Endpoint);
return;
}
if (EpAvail.Word == 0)
{ // No data available in endpoint buffer
// - Tip: A Zero Length OUT packet may be in the endpoint, and must be
// taken into account! (In this case Short Packet Transferred will be set)
HISTO(DEFAULT_HISTORY, "NoAv", 0, EpStat0, NETCHIP_READ(EP_STAT0));
break;
}
// Enough room in client's buffer for all data in the endpoint?
if (Endpoint->Priv.BytesRemaining < EpAvail.Word)
{ // Data in endpoint exceeds client's remaining buffer space
// - Transfer as many bytes as possible
// - Care must be taken to NOT disturb endpoint buffer or status bits
// so that a subsequent request can safely and accurately recover
// remaining data from the endpoint, without data loss
UINT Count = Endpoint->Priv.BytesRemaining;
// Virtualized Endpoints: Upon completion, this endpoint will be in limbo:
// - The transfer will complete, meaning the Transfer Object is closed,
// HOWEVER there will still be bytes in the endpoint!
// - The endpoint cannot be reassigned until all bytes are taken by the client!
// - Recommendation: The client completion routine should immediately start a new
// transfer to take remaining packets
NC_VIRT_EP(Endpoint->Priv.SwapCandidate = SwapCandidate_Locked;)
HISTO(DEFAULT_HISTORY, "Smal", 0, EpAvail.Word, Count);
#if NET2272_16BIT
// Recalculate loop counter for 16 bit accesses
// - Restrict transfer size to an even number of bytes
// - An odd-size request leaves one or more bytes untaken from the endpoint. For
// example if request is for 5 bytes, 4 bytes are taken (2 words read from
// endpoint), one or more bytes remain untaken in the endpoint
Count &= ~1; // Restrict to even number of bytes
Endpoint->Priv.pPkt += Count; // Byte count
Count >>= 1; // Loop count
#else
Endpoint->Priv.pPkt += Count;
#endif
// Copy bytes (or words) to memory from endpoint
// - For best performance, this loop should be optimized and written in assembler
while (Count--)
{
*(pRxBuf++) = NETCHIP_BASEADDRESS[EP_DATA].NcReg;
}
// Virtualized Endpoints: There are still bytes in the endpoint:
// - Ensure a subsequent transfer will not erroneously clear NAK OUT Packets
// by forcing NAK OUT Packets to appear FALSE
// - State of NAK OUT Packets is managed in EP_RSP:
NC_VIRT_EP(Endpoint->Priv.EpRsp = 0;)
// Complete transfer with a warning:
// - Call client completion handler
// - Tip: Bytes remain in endpoint, and *must* be taken by client soon!
// - Assert: For virtualized endpoints, locks must be set to prevent endpoint
// from getting re-assigned. Tip: This assert may fire unexpectedly if
// the Transfer Size is zero!
ASSERT(Transfer->TransferFlags & ((1<<NC_TRANSFER_FLAG_TRANSFER_LOCK) | (1<<NC_TRANSFER_FLAG_ENDPOINT_LOCK)));
Endpoint->CompletionStatus = NCSTATUS_PARTIAL_PACKET;
goto BufferTooSmall;
}
// 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_LED2(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) | // Required (for Token Notification)
0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -