📄 sausb.c
字号:
/*----------------------------------------------------------------------
* Copyright (C) 1999 Intel Corp.
*
* This file contains the USB loopback device. This device provides basic
* test capability for control and bulk transfer testing. The device
* supports a few basic general commands (SetAddress, GetDescriptor,
* SetConfiguration) and a few "vendor" specific commands.
*
* USB problems
*
* 1. Reads and writes are ignored by the interface (only writes stated in
* spec)!
* 2. Given above the design *should* provide a mechanism to verify
* the action of every read/write. For the most part it does.
* 3. EP0 FIFO reads are ignored. Length register can be used to detect this.
* Repeat the read until the count register changes.
* 4. EP0 FIFO writes are ignored. Length register can be used to detect this.
* Repeat the read until the count register changes. When the write counter
* changes you *must* wait a period of time before writing the next byte.
* Failure to do this will result in the first byte being overwritten.
* 5. EF0 IPR sets are ignored. Retry is dangerous, especially with DE side
* effect.
* Workaround to use timer to detect missed transmit, IPR clear with
* packets data still remaining indicates ignored transmit. DE set after
* last packet sent indicates ignored write on last packet. Resend whole
* packet. Alternative is to repeat set of IPR until is is visible.
* 6. EP1 FIFO reads do NOT clear RNE when the FIFO overruns! This causes
* hangs if packets larger than 16 are allowed in polled mode. Make sure
* max packet is < FIFO size in this case.
* 7. Hardware race condition on RPC and RIR. No way to repeat clear and
* guarantee the result is visible unless there are no interrupts and
* very tight loop.
* 8. Write to TPC clears FIFO loosing any data DMA'd for the next packet.
* Workaround is to setup single packet DMA and reset DMA in the interrupt
* service function for each packet.
* 9. RNE will not clear if RPE is set, probably another case of #6.
* 10. DMA will occur on a bad packet, it needs to be cuaght and undone. Due
* to this problem no DMA completion interrupts can be used (the completion
* interrupt can fire on a bad packet which can't be undone).
* 11. Set and test mechanism for UDC bits will cause hang until the USB
* clocks are running. Dont try this if the USB cable is disconnected or
* the host is stopped.
* 12. Client detects error in packet when analyzer in line does not. Possible
* problem in client receive. Effect is RPE will be set and no response is
* generated for packet (see #9). Host may or may not tolerate this.
* 14. Client does not always respond to IN packets. This can cause the host
* to declare the client dead. No workaround at this time but it has been
* observed that running the USB clock at 11.88Mhz (from the host) avoids
* the problem.
* 15. EP0 FIFO does not hold off the host or ACK the receipt of a packet until
* it is read. This means if you do not respond to the interrupt within
* the host retry period (10us or so) the host will retransmit. The new
* data will overwrite the existing FIFO data including portions currently
* being read. The result is a corrupt packet. If the packet can not
* be completely read from the FIFO in this period it will never be
* received correctly. This problem has only been observed at 148Mhz and
* only after 4K IN packet transmission.
*/
#include <string.h>
#include "dm.h"
#include "usbx.h"
#include "usbr.h"
#include "sa11x0.h"
#include "StrongArm.h"
#include "sadma.h"
#include "sairq.h"
#include "sairqh.h"
/*----------------------------------------------------------------------
* Test menu structures
*/
DM_TestFunc_T DM_EditMemory;
static DM_TestFunc_T startClient, stopClient, pollClient, showStats,
clearStats;
static char usbBanner[] = "USB Test Menu";
static DM_Test_T usbTests[] = {
0, "Start client 16", startClient, (void*)16,
1, "Start client 64", startClient, (void*)64,
2, "Start client 16 (poll)",pollClient, (void*)16,
3, "Stop USB Client", stopClient, NULL,
4, "Show Statistics", showStats, NULL,
5, "Clear Statistics", clearStats, NULL,
14, "Exit", NULL, NULL,
15, "Edit Memory", DM_EditMemory, NULL,
0, NULL
};
/*----------------------------------------------------------------------
* SA1110 USB receiver base address
*/
static volatile struct udcreg * udcP;
/*----------------------------------------------------------------------
* Register writes need to be verified. This macro loops the write until
* the effects are visible and records the number of retries.
*/
#define UDC_REG_WRITE(_struct,_ptr,_field,_val,_cmpexp,_stat) { \
int reWrites = 0; \
do { \
IOW_REG_FIELD(_struct,_ptr,_field,_val); \
reWrites++; \
} while (_cmpexp); \
udcStats._stat##Writes++; \
udcStats._stat##Rewrites += reWrites-1; \
}
#define UDC_REG_BITSET(_struct,_ptr,_field,_val,_cmpexp,_stat) { \
int reWrites = 0; \
_struct xx; \
*(unsigned int *)&xx = 0; \
xx._field = _val; \
do { \
IOW_REG_SET(_struct,_ptr,*(unsigned int*)&xx); \
reWrites++; \
} while (_cmpexp); \
udcStats._stat##Writes++; \
udcStats._stat##Rewrites += reWrites-1; \
}
#define UDC_REG_WRITEX(_setptr,_setval,_cmpexp,_stat) { \
int reWrites = 0; \
int retryCount = 1000000; \
do { \
_setptr = _setval; \
reWrites++; \
} while ((_cmpexp) && (--retryCount > 0)); \
udcStats._stat##Writes++; \
udcStats._stat##Rewrites += reWrites-1; \
}
/*----------------------------------------------------------------------
* The IN/OUT packet size may be configured between 1-255 bytes (seems like
* 16 is the only value that works reliably).
*/
#define USBR_MAX_PACKET_SIZE 16
/*----------------------------------------------------------------------
* The control FIFO is fixed at 8 bytes and will not work unless both
* host and device use 8 byte packet size.
*/
#define USBR_MAX_PACKET_SIZE_CTL 8
/*----------------------------------------------------------------------
* Variables for resend control. Keep track of last packet sent.
*/
static char * sendPacket;
static int sendPacketLength;
static int sendTotalLength;
static char * savSendPacket;
static int savSendPacketLength;
#define RESEND_INTERVAL 100 /* 100ms */
static int reSendTimerInterval;
static int readRetryCount = 100;
static int writeRetryCount = 100;
static int maxPacketSize = USBR_MAX_PACKET_SIZE;
/*----------------------------------------------------------------------
* Statistics
*/
typedef struct Udc_Stats_S {
/* General stats
*/
int usbIntCount;
/* Endpoint 0 (Command) stats
*/
int commandCount;
int sendCount;
int sendFailCount;
int reSendCount;
int readCount;
int readFailCount;
int reReadCount;
int writeCount;
int reWriteCount;
/* DMA stats
*/
int rcvDmaCount;
int xmitDmaCount;
/* Loopback stats
*/
int loopCount;
int rxCompareCount;
int rxCompareError;
/* Endpoint 1 (OUT) stats
*/
int readPacketCount;
int acceptPacketCount;
int extraFIFOReads;
int fifoReadOverrun;
int missedRIR;
int badRdPacketCount;
int dmaReadPending;
int noRPC;
int rejectPacket;
/* Endpoint 2 (IN) stats
*/
int writePacketCount;
int missedTIR;
int badWrPacketCount;
int goodWrPacketCount;
int noDMA;
/* UDCCR bit write stats
*/
int uddWrites;
int uddRewrites;
int rimWrites;
int rimRewrites;
int eimWrites;
int eimRewrites;
int timWrites;
int timRewrites;
/* UDCOMP bit write stats
*/
int compWrites;
int compRewrites;
/* UDCIMP bit write stats
*/
int cimpWrites;
int cimpRewrites;
/* UDCCS0 bit write stats
*/
int sseWrites;
int sseRewrites;
int soWrites;
int soRewrites;
int sstWrites;
int sstRewrites;
int fstWrites;
int fstRewrites;
int iprWrites;
int iprRewrites;
/* UDCCS1 bit write stats
*/
int rpcWrites;
int rpcRewrites;
int fst1Writes;
int fst1Rewrites;
int sst1Writes;
int sst1Rewrites;
/* UDCCS2 bit write stats
*/
int tpcWrites;
int tpcRewrites;
int fst2Writes;
int fst2Rewrites;
int sst2Writes;
int sst2Rewrites;
/* UDCSR bit write stats
*/
int eirWrites;
int eirRewrites;
int rirWrites;
int rirRewrites;
int tirWrites;
int tirRewrites;
int rstirWrites;
int rstirRewrites;
int susirWrites;
int susirRewrites;
int resirWrites;
int resirRewrites;
} Udc_Stats_T;
static Udc_Stats_T udcStats;
/*----------------------------------------------------------------------
* Buffer information used by interrupt service routine to dispatch
* callback functions.
*/
typedef struct bufInfo_S {
DM_Function_T * funcP;
char * buf;
char * dmaP;
void * param;
int len;
} bufInfo_T;
static DM_Function_T * thisP;
#define RX_BUFSIZE 4096
#define TX_BUFSIZE 4096
static char rxData[64*1024];
static char txData[64*1024];
static char * rxDataP;
static char * txDataP;
static bufInfo_T rcvBufs[2];
static bufInfo_T xmitBufs[2];
static int whichGetRcvBuf;
static int whichPutRcvBuf;
static int whichGetXmitBuf;
static int whichPutXmitBuf;
static void * xmitDmaP;
static void * rcvDmaP;
static int rcvPacketCount;
static int dmaInterrupts;
static int udcInterrupts;
static int udcInterruptConnected;
static DM_SerialCallback_T rcvCallback;
static DM_SerialCallback_T xmitCallback;
/*----------------------------------------------------------------------
* Timer for retries
*/
static DM_Function_T * timerP;
static DM_TimerFuncs_T * timerFuncP;
/*----------------------------------------------------------------------
* The loopback device descriptor
*/
char SA11x0_USB_DeviceDesc[18] = {
18, /* Descriptor length */
UsbDescTypeDevice, /* Device descriptor */
0, /* USB 1.00 */
1, /* USB 1.00 */
0xff, /* No class */
0xff, /* No sub class */
0xff, /* No protoocol */
USBR_MAX_PACKET_SIZE_CTL, /* Max packet size */
0x55, /* Vendor ID */
0x55, /* Vendor ID */
0x55, /* Product ID */
0x55, /* Product ID */
0, /* Device BCD */
0, /* Device BCD */
0, /* Index of Manufacturer string */
0, /* Index of Product string */
0, /* Index of Serial number string */
1 /* Number of configurations */
};
/*----------------------------------------------------------------------
* The loopback device configuration descriptor
*/
char SA11x0_USB_ConfigDesc[] = {
9, /* Descriptor length */
UsbDescTypeConfiguration, /* Configuration descriptor */
32, /* Total len LSB */
0, /* Total len MSB */
1, /* Number interfaces */
1, /* Configuration value */
0, /* Configuration string index */
0x40, /* Attributes */
1, /* Max Power */
9, /* Descriptor length */
UsbDescTypeInterface, /* Interface descriptor */
0, /* Number of interface */
0, /* Alternate setting */
2, /* Number endpoints */
0xff, /* Interface class */
0xff, /* Interface sub class */
0xff, /* Interface protocol */
0, /* Interface string descriptor */
7, /* Descriptor length */
UsbDescTypeEndpoint, /* Endpoint descriptor */
0x01, /* Endpoint address 1 (OUT) */
UsbBulk, /* Bulk transfer */
USBR_MAX_PACKET_SIZE, /* Max packet size LSB */
0, /* Max packet size MSB */
0, /* Polling interval */
7, /* Descriptor length */
UsbDescTypeEndpoint, /* Endpoint descriptor */
0x82, /* Endpoint address 2 (IN) */
UsbBulk, /* Bulk transfer */
USBR_MAX_PACKET_SIZE, /* Max packet size LSB */
0, /* Max packet size MSB */
0, /* Polling interval */
};
/*----------------------------------------------------------------------
* Forward reference
*/
static void reSendProc(void * arg);
static int receive(DM_Function_T * funcP, char * buf, int len, void * param);
static int transmit(DM_Function_T * funcP, char * buf, int len, void * param);
static int setCallback(DM_Function_T * funcP, DM_SerialCallback_T func,
int reason);
void USBR_CheckLoopback(void);
static void setup(DM_Function_T * funcP, int intEnable, int dmaEnable);
static void cleanup(DM_Function_T * funcP);
/*----------------------------------------------------------------------
* Clear stats block
*/
static
void clearUdcStats(void)
{
memset(&udcStats,0,sizeof(udcStats));
}
/*----------------------------------------------------------------------
* Poll the client
*/
static
void pollClient(DM_Function_T * funcP, void * arg)
{
DM_StartTest("USB Polled Client");
DM_Message("Hit any key to stop test");
setup(funcP,0,0); /* No interrupts w/ no DMA */
do {
USBR_CheckLoopback();
} while (!DM_StopTest(NULL));
DM_FinishTest("USB Polled Client Complete");
}
/*----------------------------------------------------------------------
* Stop the client interface
*/
static
void stopClient(DM_Function_T * funcP, void * arg)
{
DisableInterrupt(IRQ_UDC_SERVICE_REQ_VEC);
cleanup(funcP);
DM_AnyKeyToContinue("UDC processing stopped");
}
/*----------------------------------------------------------------------
* Start the client interface
*/
static
void startClient(DM_Function_T * funcP, void * arg)
{
maxPacketSize = (int)arg;
SA11x0_USB_ConfigDesc[22] = maxPacketSize;
SA11x0_USB_ConfigDesc[29] = maxPacketSize;
setup(funcP,1,1); /* Interrupts w/ DMA */
EnableInterrupt(IRQ_UDC_SERVICE_REQ_VEC);
DM_AnyKeyToContinue("UDC processing started");
}
/*----------------------------------------------------------------------
* Show statistics
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -