diff options
Diffstat (limited to 'openpicc/os/usb/USBIsr.c')
-rw-r--r-- | openpicc/os/usb/USBIsr.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/openpicc/os/usb/USBIsr.c b/openpicc/os/usb/USBIsr.c new file mode 100644 index 0000000..cbc5f85 --- /dev/null +++ b/openpicc/os/usb/USBIsr.c @@ -0,0 +1,169 @@ +/* + FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry. + + This file is part of the FreeRTOS.org distribution. + + FreeRTOS.org is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + FreeRTOS.org is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with FreeRTOS.org; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + A special exception to the GPL can be applied should you wish to distribute + a combined work that includes FreeRTOS.org, without being obliged to provide + the source code for any proprietary components. See the licensing section + of http://www.FreeRTOS.org for full details of how and when the exception + can be applied. + + *************************************************************************** + See http://www.FreeRTOS.org for documentation, latest information, license + and contact details. Please ensure to read the configuration and relevant + port sections of the online documentation. + *************************************************************************** +*/ + + +/* + BASIC INTERRUPT DRIVEN DRIVER FOR USB. + + This file contains all the usb components that must be compiled + to ARM mode. The components that can be compiled to either ARM or THUMB + mode are contained in USB-CDC.c. + +*/ + +/* Scheduler includes. */ +#include <FreeRTOS.h> +#include <task.h> +#include <queue.h> + +/* Demo application includes. */ +#include <board.h> +#include <usb.h> +#include <USB-CDC.h> + +#define usbINT_CLEAR_MASK (AT91C_UDP_TXCOMP | AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP | AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 ) +/*-----------------------------------------------------------*/ + +/* Messages and queue used to communicate between the ISR and the USB task. */ +static xISRStatus xISRMessages[usbQUEUE_LENGTH + 1]; +extern xQueueHandle xUSBInterruptQueue; +/*-----------------------------------------------------------*/ + +/* The ISR can cause a context switch so is declared naked. */ +void vUSB_ISR (void) __attribute__ ((naked)); + +/*-----------------------------------------------------------*/ + + +void +vUSB_ISR (void) +{ + /* This ISR can cause a context switch. Therefore a call to the + portENTER_SWITCHING_ISR() macro is made. This must come BEFORE any + stack variable declarations. */ + portENTER_SWITCHING_ISR (); + + /* Now variables can be declared. */ + portCHAR cTaskWokenByPost = pdFALSE; + static volatile unsigned portLONG ulNextMessage = 0; + xISRStatus *pxMessage; + unsigned portLONG ulRxBytes; + unsigned portCHAR ucFifoIndex; + + /* Use the next message from the array. */ + pxMessage = &(xISRMessages[(ulNextMessage & usbQUEUE_LENGTH)]); + ulNextMessage++; + + /* Save UDP ISR state for task-level processing. */ + pxMessage->ulISR = AT91C_BASE_UDP->UDP_ISR; + pxMessage->ulCSR0 = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0]; + + /* Clear interrupts from ICR. */ + AT91C_BASE_UDP->UDP_ICR = AT91C_BASE_UDP->UDP_IMR | AT91C_UDP_ENDBUSRES; + + + /* Process incoming FIFO data. Must set DIR (if needed) and clear RXSETUP + before exit. */ + + /* Read CSR and get incoming byte count. */ + ulRxBytes = (pxMessage->ulCSR0 >> 16) & usbRX_COUNT_MASK; + + /* Receive control transfers on endpoint 0. */ + if (pxMessage->ulCSR0 & (AT91C_UDP_RXSETUP | AT91C_UDP_RX_DATA_BK0)) + { + /* Save FIFO data buffer for either a SETUP or DATA stage */ + for (ucFifoIndex = 0; ucFifoIndex < ulRxBytes; ucFifoIndex++) + { + pxMessage->ucFifoData[ucFifoIndex] = + AT91C_BASE_UDP->UDP_FDR[usbEND_POINT_0]; + } + + /* Set direction for data stage. Must be done before RXSETUP is + cleared. */ + if ((AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] & AT91C_UDP_RXSETUP)) + { + if (ulRxBytes + && (pxMessage->ucFifoData[usbREQUEST_TYPE_INDEX] & 0x80)) + { + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] |= AT91C_UDP_DIR; + + /* Might not be wise in an ISR! */ + while (! + (AT91C_BASE_UDP-> + UDP_CSR[usbEND_POINT_0] & AT91C_UDP_DIR)); + } + + /* Clear RXSETUP */ + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] &= ~AT91C_UDP_RXSETUP; + + /* Might not be wise in an ISR! */ + while (AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] & AT91C_UDP_RXSETUP); + } + else + { + /* Clear RX_DATA_BK0 */ + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] &= ~AT91C_UDP_RX_DATA_BK0; + + /* Might not be wise in an ISR! */ + while (AT91C_BASE_UDP-> + UDP_CSR[usbEND_POINT_0] & AT91C_UDP_RX_DATA_BK0); + } + } + + /* If we received data on endpoint 1, disable its interrupts until it is + processed in the main loop */ + if (AT91C_BASE_UDP-> + UDP_CSR[usbEND_POINT_1] & (AT91C_UDP_RX_DATA_BK0 | + AT91C_UDP_RX_DATA_BK1)) + { + AT91C_BASE_UDP->UDP_IDR = AT91C_UDP_EPINT1; + } + + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] &= + ~(AT91C_UDP_TXCOMP | AT91C_UDP_STALLSENT); + + /* Clear interrupts for the other endpoints, retain data flags for endpoint + 1. */ + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_1] &= + ~(AT91C_UDP_TXCOMP | AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP); + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_2] &= ~usbINT_CLEAR_MASK; + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_3] &= ~usbINT_CLEAR_MASK; + + /* Post ISR data to queue for task-level processing */ + cTaskWokenByPost = + xQueueSendFromISR (xUSBInterruptQueue, &pxMessage, cTaskWokenByPost); + + /* Clear AIC to complete ISR processing */ + AT91C_BASE_AIC->AIC_EOICR = 0; + + /* Do a task switch if needed */ +portEXIT_SWITCHING_ISR (cTaskWokenByPost)} |