📄 sausb.c
字号:
/* Resume the DMA channel
*/
SA_ResumeDMA(rcvDmaP);
}
}
else
DM_WarnPrintf("Packet after DMA complete");
acceptPacket = 1;
}
/* Clear RPC/RIR if we accept the packet.
*/
if (acceptPacket) {
int s;
udcStats.acceptPacketCount++;
rcvPacketCount++;
/* Make sure we clear RIR first or we have a race condition with RPC
* reset. RIR should not set again while RPC is still set because
* packets are being NAKed. However, make sure we can not get
* interrupted when polling this code.
*/
if (!udcInterrupts)
s = IRQ_DisableInterrupts(CPSR_I_Bit|CPSR_F_Bit);
UDC_REG_BITSET(struct udcsrBits,&udcP->udcsr,rir,1,
udcP->udcsr.rir != 0,
rir);
/* If RPC was set clear it for next time. There is a race condition
* here because as soon as the bit actually clears the transfer
* (which is currently bing NAK'd) will proceed. This may set the bit
* again before we see it clear in which case we'll clear the second
* set). To try to preclude this in polling mode make sure we can not
* be interrupted while in this loop.
*/
#if 1
if (udcP->udccs1.rpc) {
UDC_REG_BITSET(struct udccs1Bits,&udcP->udccs1,rpc,1,
udcP->udccs1.rpc != 0,
rpc);
}
#else
/* Experiment with assembly code to clear the bit.
*/
SA_ClearBit(&udcP->udccs1,1 << 1);
#endif
if (!udcInterrupts)
IRQ_EnableInterrupts(s);
}
/* If we dont accept the packet disable interrupts until the next
* buffer arrives. Make sure we clear RIR or we'll be in an infinite loop.
*/
else {
udcStats.rejectPacket++;
UDC_REG_WRITE(struct udccrBits,&udcP->udccr,rim,1,
udcP->udccr.rim != 1,
rim);
UDC_REG_BITSET(struct udcsrBits,&udcP->udcsr,rir,1,
udcP->udcsr.rir != 0,
rir);
}
}
if (udcsr.tir) {
if (udcP->udccs2.tpc) {
/* Packet in error, back up the DMA pointer and repeat.
*/
if (udcP->udccs2.tpe) {
char * txBufP = xmitBufs[whichGetXmitBuf].dmaP;
/* Pause the DMA channel so we can access the pointers
*/
SA_PauseDMA(xmitDmaP);
/* Back up the DMA pointer to the last packet
*/
SA_SetDMABuffer(xmitDmaP,whichGetXmitBuf,txBufP);
/* Resume the DMA channel
*/
SA_ResumeDMA(xmitDmaP);
udcStats.badWrPacketCount++;
}
/* Packet not in error - update the saved DMA pointer and length
*/
else {
xmitBufs[whichGetXmitBuf].len -= maxPacketSize;
xmitBufs[whichGetXmitBuf].dmaP += maxPacketSize;
udcStats.goodWrPacketCount++;
}
/* Clear the interrupt, this needs to be done before TPC gets cleared.
*/
UDC_REG_BITSET(struct udcsrBits,&udcP->udcsr,tir,1,
udcP->udcsr.tir != 0,
tir);
/* Clear TPC, this will reset the FIFO and allow the next packet to
* be sent.
*/
UDC_REG_BITSET(struct udccs2Bits,&udcP->udccs2,tpc,1,
udcP->udccs2.tpc != 0,
tpc);
/* The transmit function can only send one packet at a time because TPC
* clears the FIFO. Check to see if we have data still to send and if so
* start the next packet.
*/
if (xmitBufs[whichGetXmitBuf].buf) {
udcStats.writePacketCount++;
DM_DbgPrintf("Tx %d, %x, len %d",
whichGetXmitBuf,
xmitBufs[whichGetXmitBuf].dmaP,
xmitBufs[whichGetXmitBuf].len);
if (xmitBufs[whichGetXmitBuf].len > 0) {
int len = xmitBufs[whichGetXmitBuf].len;
if (len > maxPacketSize)
len = maxPacketSize;
SA_StartDMA(xmitDmaP,
xmitBufs[whichGetXmitBuf].dmaP,
len,
dmaInterrupts && (xmitCallback != NULL));
}
else
xmitHandler(NULL);
}
else {
DM_WarnPrintf("Transmit w/o DMA active");
udcStats.noDMA++;
}
}
#if 0
else {
/* TIR set w/o TPC, just clear it.
*/
UDC_REG_BITSET(struct udcsrBits,&udcP->udcsr,tir,1,
udcP->udcsr.tir != 0,
tir);
}
#endif
}
if (udcsr.susir) {
UDC_REG_BITSET(struct udcsrBits,&udcP->udcsr,susir,1,
udcP->udcsr.susir != 0,
susir);
}
if (udcsr.resir) {
UDC_REG_BITSET(struct udcsrBits,&udcP->udcsr,resir,1,
udcP->udcsr.resir != 0,
resir);
}
}
/*----------------------------------------------------------------------
* Initialize the UDC
*/
void setup(DM_Function_T * funcP, int intEnable, int dmaEnable)
{
int i;
DM_DbgPrintf("Enable SA1110 USB receiver\n");
/* Enable the USB receiver, make sure we cycle disable to reset the UDC
*/
UDC_REG_WRITE(struct udccrBits,&udcP->udccr,udd,1,
udcP->udccr.udd != 1,
udd);
DM_WaitUs(100);
UDC_REG_WRITE(struct udccrBits,&udcP->udccr,udd,0,
udcP->udccr.udd != 0,
udd);
/* Disable all interrupts
*/
#if 0
IOW_REG_FIELD(struct udccrBits,&udcP->udccr,eim,1);
IOW_REG_FIELD(struct udccrBits,&udcP->udccr,rim,1);
IOW_REG_FIELD(struct udccrBits,&udcP->udccr,tim,1);
IOW_REG_FIELD(struct udccrBits,&udcP->udccr,srm,1);
IOW_REG_FIELD(struct udccrBits,&udcP->udccr,rem,1);
#endif
if (intEnable && !udcInterruptConnected) {
/* Register an interrupt handler
*/
RegisterHandler(IRQ_UDC_SERVICE_REQ_VEC,
DM_InterruptRisingEdge,
DM_InterruptDefault,
interruptHandler,
NULL);
udcInterruptConnected = 1;
}
udcInterrupts = intEnable;
/* Enable endpoint interrupts (even if we are polling we need these)
*/
#if 1
UDC_REG_WRITE(struct udccrBits,&udcP->udccr,eim,0,
udcP->udccr.eim != 0,
eim);
UDC_REG_WRITE(struct udccrBits,&udcP->udccr,rim,0,
udcP->udccr.rim != 0,
rim);
UDC_REG_WRITE(struct udccrBits,&udcP->udccr,tim,0,
udcP->udccr.tim != 0,
tim);
#endif
/* Setup the DMA channels
*/
if (dmaEnable) {
if ((xmitDmaP = (void*)SA_AllocateDMA(SA11x0_UDC_Xmit,0)) == NULL)
return;
if ((rcvDmaP = (void*)SA_AllocateDMA(SA11x0_UDC_Rcv,0)) == NULL) {
SA_ReleaseDMA(xmitDmaP);
return;
}
}
if (dmaEnable && intEnable) {
/* Register handlers for the DMA channels
*/
RegisterHandler(IRQ_CHANNEL0_VEC+SA_GetChannelDMA(rcvDmaP),
DM_InterruptRisingEdge,
DM_InterruptDefault,
rcvHandler,
NULL);
RegisterHandler(IRQ_CHANNEL0_VEC+SA_GetChannelDMA(xmitDmaP),
DM_InterruptRisingEdge,
DM_InterruptDefault,
xmitHandler,
NULL);
dmaInterrupts = 1;
}
else
dmaInterrupts = 0;
/* Open the timer
*/
if (timerP) {
timerFuncP = (DM_TimerFuncs_T*)timerP->open(timerP);
reSendTimerInterval = RESEND_INTERVAL / timerFuncP->getInterval(timerP);
}
/* Get the non cacheable address for the data buffers
*/
rxDataP = (char*)SA_NonCacheableAddress(rxData);
txDataP = (char*)SA_NonCacheableAddress(txData);
/* Fill the transmit buffer
*/
for (i=0; i < TX_BUFSIZE; i += 2) {
txDataP[i] = i % maxPacketSize;
txDataP[i+1] = i / maxPacketSize;
}
/* Set the completion callback.
*/
if (rcvDmaP)
setCallback(funcP, loopDma, DM_SerialReceiveDone);
DM_DbgPrintf("Enable SA1110 USB receiver done\n");
}
/*----------------------------------------------------------------------
* Usb interface receive function. Post the buffer to the DMA
* channel and record any callback info in the buffer info structure.
*/
static
int receive(DM_Function_T * funcP, char * buf, int len, void * param)
{
rcvBufs[whichPutRcvBuf].buf = buf;
rcvBufs[whichPutRcvBuf].param = param;
rcvBufs[whichPutRcvBuf].funcP = funcP;
rcvBufs[whichPutRcvBuf].len = len;
rcvBufs[whichPutRcvBuf].dmaP = buf;
whichPutRcvBuf ^= 1;
if (dmaInterrupts)
EnableInterrupt(IRQ_CHANNEL0_VEC+SA_GetChannelDMA(rcvDmaP));
UDC_REG_WRITE(struct udccrBits,&udcP->udccr,rim,0,
udcP->udccr.rim != 0,
rim);
SA_StartDMA(rcvDmaP, buf, len, dmaInterrupts && (rcvCallback != NULL));
return 0;
}
/*----------------------------------------------------------------------
* Usb interface transmit function. Post the buffer to the DMA
* channel and record any callback info in the buffer info structure.
*/
static
int transmit(DM_Function_T * funcP, char * buf, int len, void * param)
{
xmitBufs[whichPutXmitBuf].buf = buf;
xmitBufs[whichPutXmitBuf].param = param;
xmitBufs[whichPutXmitBuf].funcP = funcP;
xmitBufs[whichPutXmitBuf].len = len;
xmitBufs[whichPutXmitBuf].dmaP = buf;
whichPutXmitBuf ^= 1;
if (dmaInterrupts)
EnableInterrupt(IRQ_CHANNEL0_VEC+SA_GetChannelDMA(xmitDmaP));
if (udcP->udccr.tim)
DM_WarnPrintf("TIM magically disabled!");
UDC_REG_WRITE(struct udccrBits,&udcP->udccr,tim,0,
udcP->udccr.tim != 0,
tim);
/* Only send one packet at a time
*/
if (len > maxPacketSize)
len = maxPacketSize;
SA_StartDMA(xmitDmaP, buf, len, dmaInterrupts && (xmitCallback != NULL));
return 0;
}
/*----------------------------------------------------------------------
* Usb interface set callback function. Establish (or cancel) a callback
* for buffer completion.
*/
static
int setCallback(DM_Function_T * funcP, DM_SerialCallback_T func, int reason)
{
switch (reason) {
case DM_SerialReceiveDone:
rcvCallback = func;
break;
case DM_SerialTransmitDone:
xmitCallback = func;
break;
}
return 0;
}
/*----------------------------------------------------------------------
* Cleanup resources
*/
static
void cleanup(DM_Function_T * funcP)
{
/* Register an interrupt handler
*/
UnregisterHandler(IRQ_UDC_SERVICE_REQ_VEC,
interruptHandler);
udcInterruptConnected = 0;
/* Unregister handlers for the DMA channels
*/
UnregisterHandler(IRQ_CHANNEL0_VEC+SA_GetChannelDMA(rcvDmaP),
rcvHandler);
UnregisterHandler(IRQ_CHANNEL0_VEC+SA_GetChannelDMA(xmitDmaP),
xmitHandler);
/* Release the DMA channels
*/
SA_ReleaseDMA(xmitDmaP);
xmitDmaP = NULL;
SA_ReleaseDMA(rcvDmaP);
rcvDmaP = NULL;
/* Close the timer
*/
if (timerFuncP)
timerP->close(timerP);
timerFuncP = NULL;
}
/*----------------------------------------------------------------------
* Class open function. Just return the vectors
*/
static
void * open(DM_Function_T * funcP)
{
return NULL;
}
/*----------------------------------------------------------------------
* Class close function. Cleanup any allocated resources.
*/
static
void close(DM_Function_T * funcP)
{
}
/*----------------------------------------------------------------------
* Class bind function. Set the timer to use for resend.
*/
static
void bind(DM_Function_T * funcP, DM_Function_T * bindP)
{
if (bindP->class == DM_ClassTimer)
timerP = bindP;
}
/*----------------------------------------------------------------------
* Class test function.
*/
static
void test(DM_Function_T * funcP)
{
DM_DoMenu(funcP, usbBanner, usbTests);
}
void USBR_InitLoopback(void)
{
setup(thisP,0,1); /* No interrupts w/ DMA */
}
void USBR_CheckLoopback(void)
{
interruptHandler(NULL);
}
/*----------------------------------------------------------------------
* Main entry point
*/
void SA11x0_USB_Init(DM_Function_T * funcP, struct udcreg * regsP)
{
funcP->name = "USB";
funcP->version = 1;
funcP->class = DM_ClassUsb;
funcP->regsP = regsP;
funcP->subFuncs = NULL;
funcP->find = NULL;
funcP->bind = bind;
funcP->open = open;
funcP->close = close;
funcP->test = test;
udcP = regsP;
thisP = funcP;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -