/* Function: USBD_Unhalt Clears the Halt feature on the given endpoint. Parameters: eptnum - Endpoint number. */ void USBD_Unhalt(unsigned char eptnum) { Endpoint *endpoint = &(endpoints[eptnum]); // Check if the endpoint is enabled if (endpoint->state != UDP_ENDPOINT_DISABLED) { TRACE_INFO( "Unhalt%d ", eptnum); // Return endpoint to Idle state endpoint->state = UDP_ENDPOINT_IDLE; // Clear FORCESTALL flag CLEAR_CSR(eptnum, AT91C_UDP_FORCESTALL); // Reset Endpoint Fifos, beware this is a 2 steps operation AT91C_BASE_UDP->UDP_RSTEP |= 1 << eptnum; AT91C_BASE_UDP->UDP_RSTEP &= ~(1 << eptnum); } }
//----------------------------------------------------------------------------- void usb_svc_unhalt_hook(USB_DRV_INFO drv_info, HANDLE hnd) { USB_DRIVER_DATA* drv_data = drv_info->drv_data; Udp* pUDP = drv_info->hw_base; unsigned char eptnum = hnd->src.as_int; Endpoint *endpoint = &drv_data->endpoints[eptnum]; TRACE_USB(" Unhalt(%d)", eptnum); if (endpoint->state == ENDPOINT_STATE_HALTED) { // Return endpoint to Idle state endpoint->state = ENDPOINT_STATE_IDLE; // Clear FORCESTALL flag CLEAR_CSR(&pUDP->UDP_CSR[eptnum], UDP_CSR_FORCESTALL); // Reset Endpoint Fifos, beware this is a 2 steps operation pUDP->UDP_RST_EP |= 1 << eptnum; pUDP->UDP_RST_EP &= ~(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( "]"); }