📄 sausb.c
字号:
void setAddress(int addr)
{
DM_DbgPrintf("Set device address %x\n", addr);
/* Note this write will not read back until the command completes! */
IOW_REG_FIELD(struct udcarBits,&udcP->udcar,far,addr);
}
/*----------------------------------------------------------------------
* Handle a setup message
*/
static
void doSetup()
{
USB_DeviceRequest_T setup;
char * descP;
int descLength;
int length;
udcStats.commandCount++;
/* Display the setup command
*/
if (getCommand((void*)&setup) != 0) {
DM_WarnPrintf("Failed to get command\n");
sendDone(1);
return;
}
/* Dispatch the command request.
*/
switch(setup.bRequest) {
case UsbSetAddress:
DM_DbgPrintf("SETUP SET_ADDRESS %d\n", udcStats.commandCount);
setAddress(setup.wValue.d); /* Set device address */
sendDone(0);
break;
case UsbClearFeature:
DM_DbgPrintf("SETUP CLEAR_FEATURE %d\n", udcStats.commandCount);
if (setup.wValue.d == UsbFeatureHalt) { /* Halt */
switch (setup.wIndex.d) {
/* Control endpoint. Not suggested.
*/
case 0:
#if 0
UDC_REG_BITSET(struct udccs0Bits,&udcP->udccs0,fst,1,
udcP->udccs0.fst != 1,
fst);
#endif
break;
/* OUT endpoint. Set and clear FST to reset DATA0/DATA1.
*/
case 1:
UDC_REG_BITSET(struct udccs1Bits,&udcP->udccs1,fst,1,
udcP->udccs1.fst != 1,
fst1);
UDC_REG_BITSET(struct udccs1Bits,&udcP->udccs1,fst,0,
udcP->udccs1.fst != 0,
fst1);
UDC_REG_BITSET(struct udccs1Bits,&udcP->udccs1,sst,1,
udcP->udccs1.sst != 0,
sst1);
break;
/* IN endpoint. Set and clear FST to reset DATA0/DATA1.
*/
case 2:
UDC_REG_BITSET(struct udccs2Bits,&udcP->udccs2,fst,1,
udcP->udccs2.fst != 1,
fst2);
UDC_REG_BITSET(struct udccs2Bits,&udcP->udccs2,fst,0,
udcP->udccs2.fst != 0,
fst2);
UDC_REG_BITSET(struct udccs2Bits,&udcP->udccs2,sst,1,
udcP->udccs2.sst != 0,
sst2);
break;
}
}
sendDone(0);
break;
case UsbSetConfiguration:
DM_DbgPrintf("SETUP SET_CONFIGURATION %d\n", udcStats.commandCount);
sendDone(0);
break;
case UsbSetInterface:
DM_DbgPrintf("SETUP SET_INTERFACE %d\n", udcStats.commandCount);
sendDone(0);
break;
case UsbGetDescriptor:
DM_DbgPrintf("SETUP GET_DESCRIPTOR %d\n", udcStats.commandCount);
/* Find the requested descriptor
*/
if ((descP = getDescriptor(setup.wValue.desc.type,
setup.wValue.desc.index,
&descLength)) == NULL) {
DM_WarnPrintf("Unknown descriptor\n");
sendDone(0);
break;
}
/* Return up to the requested buffer size
*/
length = setup.wLength;
if (descLength < length) /* Only send back what we have room for */
length = descLength;
/* Start a 100ms timer to catch transmit drops
*/
if (timerFuncP)
timerFuncP->start(timerP, 0, reSendTimerInterval, reSendProc, NULL);
/* Clear the OPR bit and start the data phase
*/
sendCommandDone();
/* Send the first 8 bytes of data. The rest will be handled in
* subsequent interrupts.
*/
sendData(descP, length, setup.wLength);
break;
case LoopCompareRx:
{
LoopCompareReply_T r;
DM_DbgPrintf("SETUP LoopCompare %d\n", udcStats.commandCount);
/* Return up to the requested buffer size
*/
length = setup.wLength;
if (length > sizeof(LoopCompareReply_T))
length = sizeof(LoopCompareReply_T);
/* Return the buffer compare counters
*/
r.rxCompareCount = udcStats.rxCompareCount;
r.rxCompareError = udcStats.rxCompareError;
/* If we are in the middle of a DMA we need to reset
*/
if (rcvDmaP) {
DM_DbgPrintf("Check buf, w %d, b %x",
whichGetRcvBuf,
rcvBufs[whichGetRcvBuf].buf);
if (rcvBufs[whichGetRcvBuf].buf) {
SA_ClearDMA(rcvDmaP,whichGetRcvBuf);
rcvBufs[whichGetRcvBuf].buf = NULL;
whichGetRcvBuf ^= 1;
}
}
/* Start a 100ms timer to catch transmit drops
*/
if (timerFuncP)
timerFuncP->start(timerP, 0, reSendTimerInterval, reSendProc, NULL);
/* Queue a receive
*/
receive(thisP,rxDataP,RX_BUFSIZE,NULL);
/* Restart the packet counter
*/
rcvPacketCount = 0;
/* Clear the OPR bit and start the data phase
*/
sendCommandDone();
/* Send the first 8 bytes of data. The rest will be handled in
* subsequent interrupts.
*/
sendData(&r, length, setup.wLength);
}
break;
case LoopSend:
{
int len = setup.wValue.d;
DM_DbgPrintf("SETUP LoopSend %d bytes - %d\n",
len,
udcStats.commandCount);
/* Ack the command.
*/
sendDone(0);
/* Start a DMA transmit
*/
if (len > TX_BUFSIZE)
len = TX_BUFSIZE;
transmit(thisP,txDataP,len,NULL);
}
break;
default:
DM_WarnPrintf("USBR - Unsupported SETUP %x %d\n",
setup.bRequest,
udcStats.commandCount);
DM_WarnPrintf("%02x %02x %02x %02x %02x %02x %02x %02x",
setup.bmRequestType.d,
setup.bRequest,
setup.wValue.desc.index,
setup.wValue.desc.type,
setup.wIndex.d & 0xff,
(setup.wIndex.d >> 8) & 0xff,
setup.wLength & 0xff,
(setup.wLength >> 8) & 0xff);
sendDone(0);
break;
}
DM_DbgPrintf("Setup command done\n");
}
/*----------------------------------------------------------------------
* Interrupt handler
*/
static
void interruptHandler(void * arg)
{
struct udcsrBits udcsr = udcP->udcsr;
udcStats.usbIntCount++;
/* Handle the reset, the device will have gone back to internal defaults.
*/
if (udcsr.rstir) { /* Reset received */
DM_DbgPrintf("UDC port reset\n");
/* Set the default packet size
*/
UDC_REG_WRITE(struct packetBits,&udcP->udcomp,mps,maxPacketSize-1,
udcP->udcomp.mps != maxPacketSize-1,
comp);
UDC_REG_WRITE(struct packetBits,&udcP->udcimp,mps,maxPacketSize-1,
udcP->udcimp.mps != maxPacketSize-1,
cimp);
/* Clear the interrupt request bit
*/
UDC_REG_BITSET(struct udcsrBits,&udcP->udcsr,rstir,1,
udcP->udcsr.rstir != 0,
rstir);
}
/* Setup command received, extract it and go execute
*/
if (udcsr.eir) {
struct udccs0Bits udccs0 = udcP->udccs0;
/* Clear the interrupt request bit
*/
UDC_REG_BITSET(struct udcsrBits,&udcP->udcsr,eir,1,
udcP->udcsr.eir != 0,
eir);
/* If there is data to send and the transmitter is open go send
* the next packet. But, do not continue to send if the host has
* aborted the transfer or sent a new one. We'll clean up below.
*/
if ((udccs0.se == 0) && (udccs0.ipr == 0) && (udccs0.opr == 0) &&
(sendPacket))
sendData(sendPacket, sendPacketLength, sendTotalLength);
/* If stall ack, not sure what needs to be done here.
*/
if (udccs0.sst) {
DM_WarnPrintf("UDC sent STALL ack!\n");
UDC_REG_BITSET(struct udccs0Bits,&udcP->udccs0,sst,1,
udcP->udccs0.sst != 0,
sst);
}
/* If setup end, the host has aborted the transfer. Kill any
* remaining packets.
*/
if (udccs0.se) {
//if (sendPacketLength)
DM_WarnPrintf("Setup end set, host abort!\n");
sendPacketLength = 0;
sendPacket = NULL;
UDC_REG_BITSET(struct udccs0Bits,&udcP->udccs0,sse,1,
udcP->udccs0.se != 0,
sse);
}
/* If new command received ...
*/
if (udccs0.opr) {
if (sendPacket) {
DM_WarnPrintf("New setup with old data, abort old");
sendPacket = NULL;
}
DM_DbgPrintf("UDC received setup, udccs0 %x, len %d\n",
udccs0, udcP->udcwc.wc);
doSetup();
}
}
/* Recieve Interrupt
*/
if (udcsr.rir || udcP->udccs1.rpc) {
/* set flag and return
SA_USB_RxInterruptHandler(pHWHead, pRxBuffer, *pBufflen, fRXFlag);
}
int acceptPacket = 0;
/* Count missed interrupts
*/
if (udcsr.rir == 0)
udcStats.missedRIR++;
if (udcP->udccs1.rpc == 0) { /* No data to read */
udcStats.noRPC++;
acceptPacket = 1;
}
else if (udcP->udccs1.rpe) { /* Packet in error */
char * rxBufP = rcvBufs[whichGetRcvBuf].dmaP;
/* Pause the DMA channel so we can access the pointers
*/
SA_PauseDMA(rcvDmaP);
/* Back up the DMA pointer to the last packet
*/
SA_SetDMABuffer(rcvDmaP,whichGetRcvBuf,rxBufP);
/* Resume the DMA channel
*/
SA_ResumeDMA(rcvDmaP);
udcStats.badRdPacketCount++;
acceptPacket = 1;
}
/* If we are polling try to read out the data. Simulate the effects
* of the DMA mechanism.
*/
else if (rcvDmaP == NULL) {
int count = 0;
char * rxBufP = rcvBufs[whichGetRcvBuf].dmaP;
char * rxBaseP = rcvBufs[whichGetRcvBuf].buf;
udcStats.readPacketCount++;
while (udcP->udccs1.rne) {
if (rxBufP < &rxBaseP[RX_BUFSIZE])
*rxBufP++ = udcP->udcdr.data;
udcStats.extraFIFOReads++;
if (++count > maxPacketSize) {
udcStats.fifoReadOverrun++;
break;
}
/* Update the DMA pointer
*/
rcvBufs[whichGetRcvBuf].dmaP = rxBufP;
/* If we are done call the completion function
*/
if (rxBufP >= &rxDataP[RX_BUFSIZE])
rcvHandler(NULL);
}
acceptPacket = 1;
}
/* For DMA we need to clean out the part of the FIFO not
* transfered by DMA. Get the DMA pointer and move the data
* manually.
*/
else if (rcvBufs[whichGetRcvBuf].buf) {
char * p;
int count = 0;
int length;
char * rxBaseP = rcvBufs[whichGetRcvBuf].buf;
if (udcP->udccs1.rfs == 1) { /* DMA request pending, let it handle it */
udcStats.dmaReadPending++;
return;
}
udcStats.readPacketCount++;
if (rcvBufs[whichGetRcvBuf].dmaP) {
/* Pause the DMA channel so we can access the pointers
*/
SA_PauseDMA(rcvDmaP);
/* Get the current DMA pointer and calculate how much data is still
* in the FIFO.
*/
p = (char*)SA_GetDMABuffer(rcvDmaP);
length = p - rcvBufs[whichGetRcvBuf].dmaP;
if (length > maxPacketSize)
DM_WarnPrintf("DMA read multiple %d/%d",
length, maxPacketSize);
/* Read out the FIFO data. We need to drain the FIFO before continue
* but only copy up to one packet to the output buffer.
*/
while (udcP->udccs1.rne) {
char c;
if (length < maxPacketSize) {
if (p < &rxBaseP[RX_BUFSIZE])
*p++ = udcP->udcdr.data;
udcStats.extraFIFOReads++;
length++;
}
else {
c = udcP->udcdr.data;
udcStats.fifoReadOverrun++;
}
}
/* If we did not recieve all the bytes complain and realign the
* pointer (this error should not happen with the above check unless
* the length was too big to start with).
*/
if (length != maxPacketSize) {
DM_WarnPrintf("Buf %d, Pkt %d len %d/%d\n",
udcStats.rxCompareCount,
(unsigned)(p - rxDataP) / maxPacketSize,
length,
maxPacketSize);
p += maxPacketSize - length;
}
/* Update the DMA pointer. If we've finished the transfer we
* have to call the completion routine manually since the DMA
* channel will not actually complete. This is true whether
* we are polling or in interrupt mode because the FIFOs are not
* completely drained.
*/
rcvBufs[whichGetRcvBuf].dmaP = p;
if ((count=SA_SetDMABuffer(rcvDmaP,whichGetRcvBuf,p)) <= 0) {
if (count < 0)
DM_WarnPrintf("DMA channel overrun - %d\n", count);
rcvHandler(NULL);
}
else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -