/****************************************************************************** Causes the given endpoint to acknowledge the next packet it receives with a STALL handshake. ******************************************************************************/ void stallData(void) { if (UDP_ENDPOINT_IDLE != epState) return; setCSR(UDP_CSR_FORCESTALL); }
/****************************************************************************** Sends data through a USB endpoint. Parameters: data - Pointer to a buffer with the data to send. size - Size of the data buffer. callback - Optional callback function to invoke when the transfer is complete. argument - Optional argument to the callback function. ******************************************************************************/ void txUsbData(void *data, uint32_t size, TransferCallback_t callback, void *argument) { // Setup the transfer descriptor transfer.data = (void *) data; transfer.remaining = size; transfer.buffered = 0; transfer.transferred = 0; transfer.callback = callback; transfer.argument = argument; // Send the first packet epState = UDP_ENDPOINT_SENDING; while (UDP_CSR_TXPKTRDY == (UDP->UDP_CSR[EP_NUMBER] & UDP_CSR_TXPKTRDY)); writePayload(); setCSR(UDP_CSR_TXPKTRDY); }
/**************************************************************************//** \brief Startup initialization of the usb. ******************************************************************************/ void hwInitUsbDfu(void) { // enables main clock on UDP for master clock domain PMC->PMC_PCER1 = (1ul << (ID_UDP - START_ID_NUMBER_FOR_PMC1)); // enables 48 MHz clock on UDP phy for 12 MHz domain PMC->PMC_SCER = PMC_SCER_UDP; // Clear interrupt UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXSUSP | UDP_ICR_RXRSM; // enables UDP transceiver UDP->UDP_TXVC &= ~UDP_TXVC_TXVDIS; UDP->UDP_TXVC |= UDP_TXVC_PUON; // wait for usb bus reset while (!(UDP->UDP_ISR & UDP_ISR_ENDBUSRES)); // Acknowledge end of bus reset interrupt and the others UDP->UDP_ICR = UDP_ISR_ENDBUSRES | UDP_ISR_WAKEUP | UDP_ISR_RXRSM | UDP_ISR_RXSUSP; // Reset Endpoint 0 Fifos UDP->UDP_RST_EP |= UDP_RST_EP_EP0; UDP->UDP_RST_EP &= ~UDP_RST_EP_EP0; // Configure endpoint 0 setCSR(UDP_CSR_EPEDS | UDP_CSR_EPTYPE_CTRL | EP_OUT); // enumeration while (!(UDP->UDP_GLB_STAT & UDP_GLB_STAT_CONFG)) epHandler(); }
/**************************************************************************//** \brief End point handler. ******************************************************************************/ static void epHandler(void) { uint16_t i; uint8_t *ptr; // wait for transaction on 0 endpoint while (!(UDP->UDP_ISR & UDP_ISR_EP0INT)); // acknowledge end point 0 interrupt UDP->UDP_ICR = UDP_ISR_EP0INT; epStatus = UDP->UDP_CSR[EP_NUMBER]; // Handle endpoint actions // IN packet sent if (epStatus & UDP_CSR_TXCOMP) { // Check that endpoint was in Sending state if (UDP_ENDPOINT_SENDING == epState) { if (transfer.buffered < END_POINT_MAX_SIZE) { // transfer is finished transfer.transferred += transfer.buffered; transfer.buffered = 0; clearCSR(UDP_CSR_TXCOMP); // Endpoint returns in Idle state epState = UDP_ENDPOINT_IDLE; endOfTransfer(); } else { // Transfer remaining data transfer.transferred += END_POINT_MAX_SIZE; transfer.buffered -= END_POINT_MAX_SIZE; // Send next packet writePayload(); setCSR(UDP_CSR_TXPKTRDY); clearCSR(UDP_CSR_TXCOMP); } } else { // Acknowledge transaction clearCSR(UDP_CSR_TXCOMP); } } // OUT packet received if (epStatus & UDP_RXDATA) { // Check that the endpoint is in Receiving state if (UDP_ENDPOINT_RECEIVING != epState) { // Check if an ACK has been received on a Control endpoint if ((epStatus & UDP_CSR_RXBYTECNT) == 0) { // Acknowledge the data and finish the current transfer // Notify USB peripheral device that data have been read in the FIFO's Bank 0. UDP->UDP_CSR[EP_NUMBER] &= ~UDP_CSR_RX_DATA_BK0; while ((UDP->UDP_CSR[EP_NUMBER] & UDP_CSR_RX_DATA_BK0) == UDP_CSR_RX_DATA_BK0); // Endpoint returns in Idle state epState = UDP_ENDPOINT_IDLE; endOfTransfer(); } // Check if the data has been STALLed else if (epStatus & UDP_CSR_FORCESTALL) { // Discard STALLed data // Notify USB peripheral device that data have been read in the FIFO's Bank 0. UDP->UDP_CSR[EP_NUMBER] &= ~UDP_CSR_RX_DATA_BK0; while ((UDP->UDP_CSR[EP_NUMBER] & UDP_CSR_RX_DATA_BK0) == UDP_CSR_RX_DATA_BK0); } } // Endpoint is in Read state else { // Retrieve data and store it into the current transfer buffer uint16_t size = (uint16_t)(epStatus >> 16); readPayload(size); // Notify USB peripheral device that data have been read in the FIFO's Bank 0. UDP->UDP_CSR[EP_NUMBER] &= ~UDP_CSR_RX_DATA_BK0; while ((UDP->UDP_CSR[EP_NUMBER] & UDP_CSR_RX_DATA_BK0) == UDP_CSR_RX_DATA_BK0); // Check if the transfer is finished if ((transfer.remaining == 0) || (size < END_POINT_MAX_SIZE)) { // Endpoint returns in Idle state epState = UDP_ENDPOINT_IDLE; endOfTransfer(); } } } // SETUP packet received if (epStatus & UDP_CSR_RXSETUP) { // 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 ((UDP_ENDPOINT_RECEIVING == epState) || (UDP_ENDPOINT_SENDING == epState)) { // Endpoint returns in Idle state epState = UDP_ENDPOINT_IDLE; endOfTransfer(); } // Copy packet ptr = (uint8_t *)&request; for (i = 0; i < (uint16_t)(epStatus >> 16); i++) { *ptr = (uint8_t)UDP->UDP_FDR[EP_NUMBER]; ptr++; } // Set the DIR bit before clearing RXSETUP in Control IN sequence // Transfer direction is located in bit D7 of the bmRequestType field if (request.bmRequestType & 0x80) setCSR(UDP_CSR_DIR); clearCSR(UDP_CSR_RXSETUP); // Forward the request to the upper layer runtimeRequestHandler(); } // STALL sent if (epStatus & UDP_CSR_STALLSENTISOERROR) { // If the endpoint is not halted, clear the STALL condition clearCSR(UDP_CSR_STALLSENTISOERROR); clearCSR(UDP_CSR_FORCESTALL); } }
static void andCSR(Processor *p, int csr, DWORD v) { setCSR(p, csr, v & getCSR(p, csr)); }
static void orCSR(Processor *p, int csr, DWORD v) { setCSR(p, csr, v | getCSR(p, csr)); }