static void rxData(unsigned char epNum, unsigned rxMask) { DEBUGMSG( "rxMask " ); DEBUGHEX( rxMask ); DEBUGMSG( "\r\n" ); unsigned readyCount = (0 != (rxMask & AT91C_UDP_RX_DATA_BK0) ); readyCount += ( 0 != (rxMask & AT91C_UDP_RX_DATA_BK1) ); struct endpointDetails_t *const ep = &connections[epNum]; if( 2 == readyCount ){ rxMask = ep->pingPong ^ 0x42 ; if( 0 == rxMask ){ UDP_CLEAREPFLAGS( UDP->UDP_CSR+epNum, rxMask ); DEBUGMSG( "double rx on first go-round\r\n" ); return ; } } ep->pingPong = rxMask ; // keep track of last unsigned short rxLength = ( UDP->UDP_CSR[epNum] >> 16 ) & 0x7FF ; if( ep->rx_data ){ assert( endpointMaxSize[epNum] >= rxLength ); unsigned i ; unsigned char volatile *const fifo = (unsigned char *)&UDP->UDP_FDR[epNum]; for( i = 0 ; i < rxLength ; i++ ){ ep->rx_data[i] = *fifo ; } assert( ep->rx_callback ); ep->rx_callback( ep->rx_opaque, epNum, ep->rx_data, rxLength ); } // read if somebody's listening UDP_CLEAREPFLAGS( UDP->UDP_CSR+epNum, rxMask ); }
static void transmitComplete( unsigned char epNum ) { if( 0 )// != epNum ) NODEBUGMSG( "TXCOMP\r\n" ); struct endpointDetails_t *const ep = &connections[epNum]; struct transmitRequest_t *tx = (ep->txTake != ep->txAdd) ? ep->txQueue + ep->txTake : 0 ; struct transmitRequest_t *firstTx = tx ; int completed = 0 ; ep->txState = EPTX_IDLE ; if( tx && tx->txNext && SG_END(tx->txNext) ){ if( tx->flags & NEEDNULLTX ){ DEBUGMSG( "NULL tx\r\n" ); tx->flags &= ~NEEDNULLTX ; } else { if( tx->callback ) tx->callback( tx->opaque, epNum, tx->txStart ); memset( tx, 0, sizeof(*tx) ); // kill pointers ep->txTake++ ; if( ep->txTake > MAXTX_ENTRIES ) ep->txTake = 0 ; } } // done with previous request tx = (ep->txTake != ep->txAdd) ? ep->txQueue + ep->txTake : 0 ; if( 0 ){ // tx DEBUGMSG( "multi-tx 0x" ); DEBUGHEX( sg_len(tx->txStart) ); DEBUGMSG( " bytes\r\n" ); dump_sg( tx->txStart ); } if( tx ){ if( firstTx == tx ) continueTransmit(epNum,tx); else { UDP_CLEAREPFLAGS(UDP->UDP_CSR+epNum, AT91C_UDP_TXCOMP); DEBUGMSG( "nextTx 0x" ); DEBUGHEX( sg_len(tx->txStart) ); DEBUGMSG("\r\n"); startTransmit(epNum,tx); completed = 1 ; } } else { assert(ep->txTake == ep->txAdd); } if( !completed ) UDP_CLEAREPFLAGS(UDP->UDP_CSR+epNum, AT91C_UDP_TXCOMP); }
void usbll_resume( unsigned bEndpoint ) { UDP_CLEAREPFLAGS(UDP->UDP_CSR + bEndpoint, AT91C_UDP_FORCESTALL); // Reset Endpoint Fifos, beware this is a 2 steps operation UDP->UDP_RSTEP |= 1 << bEndpoint; UDP->UDP_RSTEP &= ~(1 << bEndpoint); }
int udp_read(U8* buf, int off, int len) { /* Perform a non-blocking read operation. We use double buffering (ping-pong) * operation to provide better throughput. */ int packetSize = 0, i; if (len == 0) return 0; if ((*AT91C_UDP_CSR1) & currentRxBank) // data to read { packetSize = ((*AT91C_UDP_CSR1) & AT91C_UDP_RXBYTECNT) >> 16; if (packetSize > len) packetSize = len; // Transfer the data for(i=0;i<packetSize;i++) buf[off+i] = *AT91C_UDP_FDR1; // Flip bank ENTER(); UDP_CLEAREPFLAGS(*AT91C_UDP_CSR1, currentRxBank); if (currentRxBank == AT91C_UDP_RX_DATA_BK0) { currentRxBank = AT91C_UDP_RX_DATA_BK1; } else { currentRxBank = AT91C_UDP_RX_DATA_BK0; } // We may have an enable/reset pending do it now if there is no data // in the buffers. if (delayedEnable && ((*AT91C_UDP_CSR1) & AT91C_UDP_RXBYTECNT) == 0) { delayedEnable = 0; UDP_CLEAREPFLAGS(*AT91C_UDP_CSR1, AT91C_UDP_FORCESTALL); (*AT91C_UDP_RSTEP) |= AT91C_UDP_EP1; (*AT91C_UDP_RSTEP) &= ~AT91C_UDP_EP1; } LEAVE(); // use special case for a real zero length packet so we can use it to // indicate EOF if (packetSize == 0) return -2; return packetSize; }
static void abortTransmitter(unsigned epNum) { struct endpointDetails_t *const ep = &connections[epNum]; while(ep->txTake != ep->txAdd){ struct transmitRequest_t *tx = ep->txQueue + ep->txTake ; ep->txTake++ ; if( ep->txTake > MAXTX_ENTRIES ) ep->txTake = 0 ; usbll_tx_callback_t callback = tx->callback ; if( callback ) callback( tx->opaque, epNum, tx->txStart ); memset( tx, 0, sizeof(*tx) ); // kill pointers } ep->txState = EPTX_IDLE ; UDP_CLEAREPFLAGS(UDP->UDP_CSR+epNum, AT91C_UDP_TXCOMP|AT91C_UDP_TXPKTRDY); }
//------------------------------------------------------------------------------ // \brief Clears the correct RX flag in an endpoint status register // \param pUsb Pointer to a S_usb instance // \param bEndpoint Index of endpoint // \see S_usb_endpoint // \see S_usb //------------------------------------------------------------------------------ static void UDP_ClearRXFlag(const S_usb * pUsb, unsigned char bEndpoint) { S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint); // Clear flag UDP_CLEAREPFLAGS(pUsb, bEndpoint, pEndpoint->dFlag); // Swap banks if (pEndpoint->dFlag == AT91C_UDP_RX_DATA_BK0) { if (pEndpoint->dNumFIFO > 1) { // Swap bank if in dual-fifo mode pEndpoint->dFlag = AT91C_UDP_RX_DATA_BK1; } } else { pEndpoint->dFlag = AT91C_UDP_RX_DATA_BK0; } }
/* called by the main application to poll for events */ void usbll_poll( void ) { int epNum ; unsigned gstate ; unsigned isr = UDP->UDP_ISR ; if( isr != prevISR ){ prevISR = isr ; } if( isr & AT91C_UDP_EPINT0 ){ UDP->UDP_ICR = AT91C_UDP_EPINT0 ; } if( isr & AT91C_UDP_WAKEUP ){ DEBUGMSG( "UDP_WAKEUP\r\n" ); UDP->UDP_ICR = AT91C_UDP_WAKEUP ; } if( isr & AT91C_UDP_RXRSM ){ DEBUGMSG( "UDP_RXRSM\r\n" ); UDP->UDP_ICR = AT91C_UDP_RXRSM ; } if( isr & AT91C_UDP_EXTRSM ){ DEBUGMSG( "UDP_EXTRSM\r\n" ); UDP->UDP_ICR = AT91C_UDP_EXTRSM ; } if( isr & AT91C_UDP_SOFINT ){ // DEBUGMSG( "UDP_SOFINT\r\n" ); UDP->UDP_ICR = AT91C_UDP_SOFINT ; } if( isr & AT91C_UDP_ENDBUSRES ){ // write( DEFUART, "GLBSTATE == " ); writeHex( DEFUART, UDP->UDP_GLBSTATE ); write( DEFUART, "\r\n" ); UDP->UDP_FADDR = AT91C_UDP_FEN ; UDP_CLEAREPFLAGS(&UDP->UDP_GLBSTATE,AT91C_UDP_CONFG|AT91C_UDP_FADDEN); UDP->UDP_RSTEP = 0xffffffff ; UDP->UDP_RSTEP = 0 ; UDP_SETEPFLAGS(UDP->UDP_CSR + 0, AT91C_UDP_EPEDS); UDP_CLEAREPFLAGS(UDP->UDP_CSR + 0, AT91C_UDP_DIR); UDP->UDP_ICR = AT91C_UDP_ENDBUSRES ; abortTransmitters(); // write( DEFUART, "UDP_ENDBUSRES 0x" );writeHex( DEFUART, UDP->UDP_GLBSTATE ); write( DEFUART, "\r\n" ); } gstate = UDP->UDP_GLBSTATE; for( epNum = 0 ; epNum < UDP_MAXENDPOINTS ; epNum++ ){ unsigned int dStatus = UDP->UDP_CSR[epNum]; if( dStatus & AT91C_UDP_TXCOMP ){ transmitComplete(epNum); } // transmit completed if( dStatus & AT91C_UDP_RXSETUP ){ unsigned char setupBuf[16]; unsigned short rxLength = ( dStatus >> 16 ) & 0x7FF ; if( sizeof(struct S_usb_request) <= rxLength ){ struct S_usb_request const *rxSetup = (struct S_usb_request const *)setupBuf ; rxLength = sizeof(*rxSetup); unsigned i ; unsigned char volatile *const fifo = (unsigned char *)&UDP->UDP_FDR[epNum]; for( i = 0 ; i < rxLength ; i++ ){ setupBuf[i] = *fifo ; } if( rxSetup->bmRequestType & 0x80) { UDP_SETEPFLAGS(UDP->UDP_CSR + epNum, AT91C_UDP_DIR); } UDP_CLEAREPFLAGS(UDP->UDP_CSR + epNum, AT91C_UDP_RXSETUP); if( 0 != (UDP->UDP_CSR[epNum] & (AT91C_UDP_TXPKTRDY|AT91C_UDP_TXCOMP|AT91C_UDP_STALLSENT)) ){ write( DEFUART, "rxSetup: txPending\r\n" ); } if( setupCallback ){ completeTransmit(epNum); setupCallback( setupOpaque, setupBuf, rxLength ); } } else { write( DEFUART, "rxSetup too small 0x" ); writeHexChar( DEFUART, rxLength ); write( DEFUART, "\r\n" ); UDP_CLEAREPFLAGS(UDP->UDP_CSR + epNum, AT91C_UDP_RXSETUP); } } if( dStatus & AT91C_UDP_STALLSENT ){ UDP_CLEAREPFLAGS(UDP->UDP_CSR + epNum, AT91C_UDP_STALLSENT); } unsigned int rxMask = dStatus & (AT91C_UDP_RX_DATA_BK0|AT91C_UDP_RX_DATA_BK1); if( rxMask ){ rxData(epNum,rxMask); } // received something }
//------------------------------------------------------------------------------ // \brief Endpoint interrupt handler. // // Handle IN/OUT transfers, received SETUP packets and STALLing // \param pUsb Pointer to a S_usb instance // \param bEndpoint Index of endpoint // \see S_usb //------------------------------------------------------------------------------ static void UDP_EndpointHandler(const S_usb *pUsb, unsigned char bEndpoint) { S_usb_endpoint *pEndpoint = USB_GetEndpoint(pUsb, bEndpoint); AT91PS_UDP pInterface = UDP_GetDriverInterface(pUsb); unsigned int dStatus = pInterface->UDP_CSR[bEndpoint]; TRACE_DEBUG_L("Ept%d ", bEndpoint); // Handle interrupts // IN packet sent if (ISSET(dStatus, AT91C_UDP_TXCOMP)) { TRACE_DEBUG_L("Wr "); // Check that endpoint was in Write state if (pEndpoint->dState == endpointStateWrite) { // End of transfer ? if ((pEndpoint->dBytesBuffered < pEndpoint->wMaxPacketSize) || (!ISCLEARED(dStatus, AT91C_UDP_EPTYPE) && (pEndpoint->dBytesRemaining == 0) && (pEndpoint->dBytesBuffered == pEndpoint->wMaxPacketSize))) { TRACE_DEBUG_L("%d ", pEndpoint->dBytesBuffered); pEndpoint->dBytesTransferred += pEndpoint->dBytesBuffered; pEndpoint->dBytesBuffered = 0; // Disable interrupt if this is not a control endpoint if (!ISCLEARED(dStatus, AT91C_UDP_EPTYPE)) { SET(pInterface->UDP_IDR, 1 << bEndpoint); } UDP_EndOfTransfer(pEndpoint, USB_STATUS_SUCCESS); } else { // Transfer remaining data TRACE_DEBUG_L("%d ", pEndpoint->wMaxPacketSize); pEndpoint->dBytesTransferred += pEndpoint->wMaxPacketSize; pEndpoint->dBytesBuffered -= pEndpoint->wMaxPacketSize; // Send next packet if (pEndpoint->dNumFIFO == 1) { // No double buffering UDP_WritePayload(pUsb, bEndpoint); UDP_SETEPFLAGS(pUsb, bEndpoint, AT91C_UDP_TXPKTRDY); } else { // Double buffering UDP_SETEPFLAGS(pUsb, bEndpoint, AT91C_UDP_TXPKTRDY); UDP_WritePayload(pUsb, bEndpoint); } } } // Acknowledge interrupt UDP_CLEAREPFLAGS(pUsb, bEndpoint, AT91C_UDP_TXCOMP); } // OUT packet received if (ISSET(dStatus, AT91C_UDP_RX_DATA_BK0) || ISSET(dStatus, AT91C_UDP_RX_DATA_BK1)) { TRACE_DEBUG_L("Rd "); // Check that the endpoint is in Read state if (pEndpoint->dState != endpointStateRead) { // Endpoint is NOT in Read state if (ISCLEARED(dStatus, AT91C_UDP_EPTYPE) && ISCLEARED(dStatus, 0xFFFF0000)) { // Control endpoint, 0 bytes received // Acknowledge the data and finish the current transfer TRACE_DEBUG_L("Ack "); UDP_ClearRXFlag(pUsb, bEndpoint); UDP_EndOfTransfer(pEndpoint, USB_STATUS_SUCCESS); } else if (ISSET(dStatus, AT91C_UDP_FORCESTALL)) { // Non-control endpoint // Discard stalled data TRACE_DEBUG_L("Disc "); UDP_ClearRXFlag(pUsb, bEndpoint); } else { // Non-control endpoint // Nak data TRACE_DEBUG_L("Nak "); SET(pInterface->UDP_IDR, 1 << bEndpoint); } } else { // Endpoint is in Read state // Retrieve data and store it into the current transfer buffer unsigned short wPacketSize = (unsigned short) (dStatus >> 16); TRACE_DEBUG_L("%d ", wPacketSize); UDP_GetPayload(pUsb, bEndpoint, wPacketSize); UDP_ClearRXFlag(pUsb, bEndpoint); if ((pEndpoint->dBytesRemaining == 0) || (wPacketSize < pEndpoint->wMaxPacketSize)) { // Disable interrupt if this is not a control endpoint if (!ISCLEARED(dStatus, AT91C_UDP_EPTYPE)) { SET(pInterface->UDP_IDR, 1 << bEndpoint); } UDP_EndOfTransfer(pEndpoint, USB_STATUS_SUCCESS); } } }