/* Function: UDP_DisableEndpoints Disables all endpoints of the UDP peripheral except Control endpoint 0. */ static void UDP_DisableEndpoints() { unsigned char eptnum; // Disable each endpoint, terminating any pending transfer for (eptnum = 1; eptnum < BOARD_USB_NUMENDPOINTS; eptnum++) { UDP_EndOfTransfer(eptnum, USBD_STATUS_ABORTED); endpoints[eptnum].state = UDP_ENDPOINT_DISABLED; } }
//------------------------------------------------------------------------------ // \brief Disable all endpoints (except control endpoint 0), aborting current // transfers if necessary. // \param pUsb Pointer to a S_usb instance //------------------------------------------------------------------------------ static void UDP_DisableEndpoints(const S_usb *pUsb) { S_usb_endpoint *pEndpoint; unsigned char bEndpoint; // For each endpoint, if it is enabled, disable it and invoke the callback // Control endpoint 0 is not disabled for (bEndpoint = 1; bEndpoint < pUsb->dNumEndpoints; bEndpoint++) { pEndpoint = USB_GetEndpoint(pUsb, bEndpoint); UDP_EndOfTransfer(pEndpoint, USB_STATUS_RESET); pEndpoint->dState = endpointStateDisabled; } }
/* Function: USBD_ConfigureEndpoint Configures an endpoint according to its Endpoint Descriptor. Parameters: descriptor - Pointer to an Endpoint descriptor. */ void USBD_ConfigureEndpoint(const USBEndpointDescriptor *descriptor) { Endpoint *endpoint; unsigned char eptnum; unsigned char type; unsigned char direction; // NULL descriptor -> Control endpoint 0 if (descriptor == 0) { eptnum = 0; endpoint = &(endpoints[eptnum]); type = USBEndpointDescriptor_CONTROL; direction = 0; endpoint->size = BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0); } else { eptnum = USBEndpointDescriptor_GetNumber(descriptor); endpoint = &(endpoints[eptnum]); type = USBEndpointDescriptor_GetType(descriptor); direction = USBEndpointDescriptor_GetDirection(descriptor); endpoint->size = USBEndpointDescriptor_GetMaxPacketSize(descriptor); } // Abort the current transfer is the endpoint was configured and in // Write or Read state if ((endpoint->state == UDP_ENDPOINT_RECEIVING) || (endpoint->state == UDP_ENDPOINT_SENDING)) { UDP_EndOfTransfer(eptnum, USBD_STATUS_RESET); } endpoint->state = UDP_ENDPOINT_IDLE; // Reset Endpoint Fifos AT91C_BASE_UDP->UDP_RSTEP |= (1 << eptnum); AT91C_BASE_UDP->UDP_RSTEP &= ~(1 << eptnum); // Configure endpoint SET_CSR(eptnum, AT91C_UDP_EPEDS | (type << 8) | (direction << 10)); if (type == USBEndpointDescriptor_CONTROL) { AT91C_BASE_UDP->UDP_IER = (1 << eptnum); } TRACE_INFO( "\r\n# CfgEpt%d ", eptnum); }
/* Function: USBD_Halt Sets the HALT feature on the given endpoint (if not already in this state). Parameters: eptnum - Endpoint number. */ void USBD_Halt(unsigned char eptnum) { Endpoint *endpoint = &(endpoints[eptnum]); // Check that endpoint is enabled and not already in Halt state if ((endpoint->state != UDP_ENDPOINT_DISABLED) && (endpoint->state != UDP_ENDPOINT_HALTED)) { TRACE_INFO( "Halt%d ", eptnum); // Abort the current transfer if necessary UDP_EndOfTransfer(eptnum, USBD_STATUS_ABORTED); // Put endpoint into Halt state SET_CSR(eptnum, AT91C_UDP_FORCESTALL); endpoint->state = UDP_ENDPOINT_HALTED; // Enable the endpoint interrupt AT91C_BASE_UDP->UDP_IER = 1 << eptnum; } }
/* Function: UDP_EndpointHandler Endpoint interrupt handler. Manages IN, OUT & SETUP transaction, as well as the STALL condition. Parameters: eptnum - Number of the endpoint to handle interrupt for. */ static void UDP_EndpointHandler(unsigned char eptnum) { Endpoint *endpoint = &(endpoints[eptnum]); Transfer *transfer = &(endpoint->transfer); unsigned int status = AT91C_BASE_UDP->UDP_CSR[eptnum]; //TRACE_INFO( "Ept%d ", eptnum); //TRACE_INFO( "["); // Handle interrupts // IN packet sent if ((status & AT91C_UDP_TXCOMP) != 0) { //TRACE_INFO( "Wr "); // Check that endpoint was in Sending state if (endpoint->state == UDP_ENDPOINT_SENDING) { // End of transfer ? if (UDP_IsTransferFinished(eptnum)) { // TRACE_INFO( "%d ", transfer->buffered); transfer->transferred += transfer->buffered; transfer->buffered = 0; // Disable interrupt if this is not a control endpoint if ((status & AT91C_UDP_EPTYPE) != AT91C_UDP_EPTYPE_CTRL) { AT91C_BASE_UDP->UDP_IDR = 1 << eptnum; } UDP_EndOfTransfer(eptnum, USBD_STATUS_SUCCESS); CLEAR_CSR(eptnum, AT91C_UDP_TXCOMP); } else { // Transfer remaining data //TRACE_INFO( "PQ:%d ", endpoint->size); transfer->transferred += endpoint->size; transfer->buffered -= endpoint->size; // Send next packet if (BOARD_USB_ENDPOINTS_BANKS(eptnum) == 1) { // No double buffering UDP_WritePayload(eptnum); SET_CSR(eptnum, AT91C_UDP_TXPKTRDY); CLEAR_CSR(eptnum, AT91C_UDP_TXCOMP); } else { // Double buffering SET_CSR(eptnum, AT91C_UDP_TXPKTRDY); CLEAR_CSR(eptnum, AT91C_UDP_TXCOMP); UDP_WritePayload(eptnum); } } } else { // Acknowledge interrupt CLEAR_CSR(eptnum, AT91C_UDP_TXCOMP); } } // OUT packet received if ((status & UDP_RXDATA) != 0) { //TRACE_INFO( "Rd "); // Check that the endpoint is in Receiving state if (endpoint->state != UDP_ENDPOINT_RECEIVING) { // Check if an ACK has been received on a Control endpoint if (((status & AT91C_UDP_EPTYPE) == AT91C_UDP_EPTYPE_CTRL) && ((status & AT91C_UDP_RXBYTECNT) == 0)) { // Acknowledge the data and finish the current transfer ///TRACE_INFO( "[%d]Ack ",eptnum); UDP_ClearRxFlag(eptnum); UDP_EndOfTransfer(eptnum, USBD_STATUS_SUCCESS); } // Check if the data has been STALLed else if ((status & AT91C_UDP_FORCESTALL) != 0) { // Discard STALLed data TRACE_INFO( "[%d]Disc ",eptnum); UDP_ClearRxFlag(eptnum); } // NAK the data else { TRACE_INFO( "[%d]Nak ",eptnum); AT91C_BASE_UDP->UDP_IDR = 1 << eptnum; } } // Endpoint is in Read state else { // Retrieve data and store it into the current transfer buffer unsigned short size = (unsigned short) (status >> 16); //TRACE_INFO( "-[%d]-", size); //TRACE_INFO( "Rec "); UDP_ReadPayload(eptnum, size); UDP_ClearRxFlag(eptnum); // Check if the transfer is finished if ((transfer->remaining == 0) || (size < endpoint->size)) { // Disable interrupt if this is not a control endpoint if ((status & AT91C_UDP_EPTYPE) != AT91C_UDP_EPTYPE_CTRL) { AT91C_BASE_UDP->UDP_IDR = 1 << eptnum; } UDP_EndOfTransfer(eptnum, USBD_STATUS_SUCCESS); } } } // SETUP packet received if ((status & AT91C_UDP_RXSETUP) != 0) { //TRACE_INFO( "Stp "); // If a transfer was pending, complete it // Handles the case where during the status phase of a control write // transfer, the host receives the device ZLP and ack it, but the ack // is not received by the device if ((endpoint->state == UDP_ENDPOINT_RECEIVING) || (endpoint->state == UDP_ENDPOINT_SENDING)) { UDP_EndOfTransfer(eptnum, USBD_STATUS_SUCCESS); } USBGenericRequest request; UDP_ReadRequest(&request); // Set the DIR bit before clearing RXSETUP in Control IN sequence if (USBGenericRequest_GetDirection(&request) == USBGenericRequest_IN) { SET_CSR(eptnum, AT91C_UDP_DIR); } CLEAR_CSR(eptnum, AT91C_UDP_RXSETUP); // Forward the request to the upper layer USBDCallbacks_RequestReceived(&request);//------------------------------------ } // STALL sent if ((status & AT91C_UDP_STALLSENT) != 0) { TRACE_INFO( "STA "); // If the endpoint is not halted, clear the STALL condition CLEAR_CSR(eptnum, AT91C_UDP_STALLSENT); if (endpoint->state != UDP_ENDPOINT_HALTED) { CLEAR_CSR(eptnum, AT91C_UDP_FORCESTALL); } } //TRACE_INFO( "]"); }
//------------------------------------------------------------------------------ // \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); } } }