diff options
Diffstat (limited to 'openpicc/os/usb')
-rw-r--r-- | openpicc/os/usb/USB-CDC.c | 953 | ||||
-rw-r--r-- | openpicc/os/usb/USB-CDC.h | 87 | ||||
-rw-r--r-- | openpicc/os/usb/USBIsr.c | 169 | ||||
-rw-r--r-- | openpicc/os/usb/descriptors.h | 190 | ||||
-rw-r--r-- | openpicc/os/usb/usb.h | 146 |
5 files changed, 1545 insertions, 0 deletions
diff --git a/openpicc/os/usb/USB-CDC.c b/openpicc/os/usb/USB-CDC.c new file mode 100644 index 0000000..4496c55 --- /dev/null +++ b/openpicc/os/usb/USB-CDC.c @@ -0,0 +1,953 @@ +/* + 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. + + Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along + with commercial development and support options. + *************************************************************************** +*/ + +/* + USB Communications Device Class driver. + Implements task vUSBCDCTask and provides an Abstract Control Model serial + interface. Control is through endpoint 0, device-to-host notification is + provided by interrupt-in endpoint 3, and raw data is transferred through + bulk endpoints 1 and 2. + + - developed from original FreeRTOS HID example by Scott Miller + - modified to support 3.2 GCC by najay +*/ + +/* Standard includes. */ +#include <string.h> +#include <stdio.h> + +/* Demo board includes. */ +#include <board.h> + +/* Scheduler includes. */ +#include <FreeRTOS.h> +#include <task.h> +#include <queue.h> + +/* Demo app includes. */ +#include <USB-CDC.h> +#include <descriptors.h> + +#define usbNO_BLOCK ( ( portTickType ) 0 ) + +/* Reset all endpoints */ +static void prvResetEndPoints (void); + +/* Clear pull up resistor to detach device from host */ +static void vDetachUSBInterface (void); + +/* Set up interface and initialize variables */ +static void vInitUSBInterface (void); + +/* Handle control endpoint events. */ +static void prvProcessEndPoint0Interrupt (xISRStatus * pxMessage); + +/* Handle standard device requests. */ +static void prvHandleStandardDeviceRequest (xUSB_REQUEST * pxRequest); + +/* Handle standard interface requests. */ +static void prvHandleStandardInterfaceRequest (xUSB_REQUEST * pxRequest); + +/* Handle endpoint requests. */ +static void prvHandleStandardEndPointRequest (xUSB_REQUEST * pxRequest); + +/* Handle class interface requests. */ +static void prvHandleClassInterfaceRequest (xUSB_REQUEST * pxRequest); + +/* Prepare control data transfer. prvSendNextSegment starts transfer. */ +static void prvSendControlData (unsigned portCHAR * pucData, + unsigned portSHORT usRequestedLength, + unsigned portLONG ulLengthLeftToSend, + portLONG lSendingDescriptor); + +/* Send next segment of data for the control transfer */ +static void prvSendNextSegment (void); + +/* Send stall - used to respond to unsupported requests */ +static void prvSendStall (void); + +/* Send a zero-length (null) packet */ +static void prvSendZLP (void); + +/* Handle requests for standard interface descriptors */ +static void prvGetStandardInterfaceDescriptor (xUSB_REQUEST * pxRequest); + +/*------------------------------------------------------------*/ + +/* File scope static variables */ +static unsigned portCHAR ucUSBConfig = (unsigned portCHAR) 0; +static unsigned portLONG ulReceivedAddress = (unsigned portLONG) 0; +static eDRIVER_STATE eDriverState = eNOTHING; + +/* Incoming and outgoing control data structures */ +static xCONTROL_MESSAGE pxControlTx; +static xCONTROL_MESSAGE pxControlRx; + +/* Queue holding pointers to pending messages */ +xQueueHandle xUSBInterruptQueue; + +/* Queues used to hold received characters, and characters waiting to be +transmitted. Rx queue must be larger than FIFO size. */ +static xQueueHandle xRxCDC; +static xQueueHandle xTxCDC; + +/* Line coding - 115,200 baud, N-8-1 */ +static const unsigned portCHAR pxLineCoding[] = + { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 }; + +/* Status variables. */ +static unsigned portCHAR ucControlState; +static unsigned int uiCurrentBank; + + +/*------------------------------------------------------------*/ + + +void +vUSBCDCTask (void *pvParameters) +{ + xISRStatus *pxMessage; + unsigned portLONG ulStatus; + unsigned portLONG ulRxBytes; + unsigned portCHAR ucByte; + portBASE_TYPE xByte; + + (void) pvParameters; + + /* Disconnect USB device from hub. For debugging - causes host to register reset */ + portENTER_CRITICAL (); + vDetachUSBInterface (); + portEXIT_CRITICAL (); + + vTaskDelay (portTICK_RATE_MS * 60); + + /* Init USB interface */ + portENTER_CRITICAL (); + vInitUSBInterface (); + portEXIT_CRITICAL (); + + /* Main task loop. Process incoming endpoint 0 interrupts, handle data transfers. */ + + for (;;) + { + /* Look for data coming from the ISR. */ + if (xQueueReceive (xUSBInterruptQueue, &pxMessage, usbSHORTEST_DELAY)) + { + if (pxMessage->ulISR & AT91C_UDP_EPINT0) + { + /* All endpoint 0 interrupts are handled here. */ + prvProcessEndPoint0Interrupt (pxMessage); + } + + if (pxMessage->ulISR & AT91C_UDP_ENDBUSRES) + { + /* End of bus reset - reset the endpoints and de-configure. */ + prvResetEndPoints (); + } + } + + /* See if we're ready to send and receive data. */ + if (eDriverState == eREADY_TO_SEND && ucControlState) + { + if ((! + (AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_2] & AT91C_UDP_TXPKTRDY)) + && uxQueueMessagesWaiting (xTxCDC)) + { + for (xByte = 0; xByte < 64; xByte++) + { + if (!xQueueReceive (xTxCDC, &ucByte, 0)) + { + /* No data buffered to transmit. */ + break; + } + + /* Got a byte to transmit. */ + AT91C_BASE_UDP->UDP_FDR[usbEND_POINT_2] = ucByte; + } + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_2] |= AT91C_UDP_TXPKTRDY; + } + + /* Check for incoming data (host-to-device) on endpoint 1. */ + while (AT91C_BASE_UDP-> + UDP_CSR[usbEND_POINT_1] & (AT91C_UDP_RX_DATA_BK0 | + AT91C_UDP_RX_DATA_BK1)) + { + ulRxBytes = + (AT91C_BASE_UDP-> + UDP_CSR[usbEND_POINT_1] >> 16) & usbRX_COUNT_MASK; + + /* Only process FIFO if there's room to store it in the queue */ + if (ulRxBytes < + (USB_CDC_QUEUE_SIZE - uxQueueMessagesWaiting (xRxCDC))) + { + while (ulRxBytes--) + { + ucByte = AT91C_BASE_UDP->UDP_FDR[usbEND_POINT_1]; + xQueueSend (xRxCDC, &ucByte, 0); + } + + /* Release the FIFO */ + portENTER_CRITICAL (); + { + ulStatus = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_1]; + usbCSR_CLEAR_BIT (&ulStatus, uiCurrentBank); + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_1] = ulStatus; + } + portEXIT_CRITICAL (); + + /* Re-enable endpoint 1's interrupts */ + AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1; + + /* Update the current bank in use */ + if (uiCurrentBank == AT91C_UDP_RX_DATA_BK0) + { + uiCurrentBank = AT91C_UDP_RX_DATA_BK1; + } + else + { + uiCurrentBank = AT91C_UDP_RX_DATA_BK0; + } + + } + else + { + break; + } + } + } + } +} + +/*------------------------------------------------------------*/ + +void +vUSBSendByte (portCHAR cByte) +{ + /* Queue the byte to be sent. The USB task will send it. */ + xQueueSend (xTxCDC, &cByte, usbNO_BLOCK); +} + +/*------------------------------------------------------------*/ + +portLONG +vUSBRecvByte (portCHAR *cByte, portLONG size, portTickType xTicksToWait) +{ + portLONG res; + if(size<=0 || !cByte || !xRxCDC) + return 0; + + res=0; + while(size-- && xQueueReceive(xRxCDC, cByte++, xTicksToWait)) + res++; + + return res; +} + +/*------------------------------------------------------------*/ + +static void +prvSendZLP (void) +{ + unsigned portLONG ulStatus; + + /* Wait until the FIFO is free - even though we are not going to use it. + THERE IS NO TIMEOUT HERE! */ + while (AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] & AT91C_UDP_TXPKTRDY) + { + vTaskDelay (usbSHORTEST_DELAY); + } + + portENTER_CRITICAL (); + { + /* Cancel any further pending data */ + pxControlTx.ulTotalDataLength = pxControlTx.ulNextCharIndex; + + /* Set the TXPKTRDY bit to cause a transmission with no data. */ + ulStatus = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0]; + usbCSR_SET_BIT (&ulStatus, AT91C_UDP_TXPKTRDY); + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] = ulStatus; + } + portEXIT_CRITICAL (); +} + +/*------------------------------------------------------------*/ + +static void +prvSendStall (void) +{ + unsigned portLONG ulStatus; + + portENTER_CRITICAL (); + { + /* Force a stall by simply setting the FORCESTALL bit in the CSR. */ + ulStatus = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0]; + usbCSR_SET_BIT (&ulStatus, AT91C_UDP_FORCESTALL); + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] = ulStatus; + } + portEXIT_CRITICAL (); +} + +/*------------------------------------------------------------*/ + +static void +prvResetEndPoints (void) +{ + unsigned portLONG ulTemp; + + eDriverState = eJUST_RESET; + ucControlState = 0; + + /* Reset all the end points. */ + AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK; + AT91C_BASE_UDP->UDP_RSTEP = (unsigned portLONG) 0x00; + + /* Enable data to be sent and received. */ + AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN; + + /* Repair the configuration end point. */ + portENTER_CRITICAL (); + { + ulTemp = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0]; + usbCSR_SET_BIT (&ulTemp, + ((unsigned portLONG) (AT91C_UDP_EPEDS | + AT91C_UDP_EPTYPE_CTRL))); + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] = ulTemp; + AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0; + } + portEXIT_CRITICAL (); + uiCurrentBank = AT91C_UDP_RX_DATA_BK0; +} + +/*------------------------------------------------------------*/ + +static void +prvProcessEndPoint0Interrupt (xISRStatus * pxMessage) +{ + static xUSB_REQUEST xRequest; + unsigned portLONG ulRxBytes; + + /* Get number of bytes received, if any */ + ulRxBytes = pxMessage->ulCSR0 >> 16; + ulRxBytes &= usbRX_COUNT_MASK; + + if (pxMessage->ulCSR0 & AT91C_UDP_TXCOMP) + { + /* We received a TX complete interrupt. What we do depends on + what we sent to get this interrupt. */ + + if (eDriverState == eJUST_GOT_CONFIG) + { + /* We sent an acknowledgement of a SET_CONFIG request. We + are now at the end of the enumeration. + + TODO: Config 0 sets unconfigured state, should enter Address state. + Request for unsupported config should stall. */ + AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG; + + /* Set up endpoints */ + portENTER_CRITICAL (); + { + unsigned portLONG ulTemp; + + /* Set endpoint 1 to bulk-out */ + ulTemp = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_1]; + usbCSR_SET_BIT (&ulTemp, + AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT); + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_1] = ulTemp; + AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1; + /* Set endpoint 2 to bulk-in */ + ulTemp = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_2]; + usbCSR_SET_BIT (&ulTemp, + AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN); + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_2] = ulTemp; + AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT2; + /* Set endpoint 3 to interrupt-in, enable it, and enable interrupts */ + ulTemp = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_3]; + usbCSR_SET_BIT (&ulTemp, + AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN); + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_3] = ulTemp; + /*AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT3 ); */ + } + portEXIT_CRITICAL (); + + eDriverState = eREADY_TO_SEND; + } + else if (eDriverState == eJUST_GOT_ADDRESS) + { + /* We sent an acknowledgement of a SET_ADDRESS request. Move + to the addressed state. */ + if (ulReceivedAddress != (unsigned portLONG) 0) + { + AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN; + } + else + { + AT91C_BASE_UDP->UDP_GLBSTATE = 0; + } + + AT91C_BASE_UDP->UDP_FADDR = (AT91C_UDP_FEN | ulReceivedAddress); + eDriverState = eNOTHING; + } + else + { + /* The TXCOMP was not for any special type of transmission. See + if there is any more data to send. */ + prvSendNextSegment (); + } + } + + if (pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0) + { + /* Received a control data packet. May be a 0-length ACK or a data stage. */ + unsigned portCHAR ucBytesToGet; + + /* Got data. Cancel any outgoing data. */ + pxControlTx.ulNextCharIndex = pxControlTx.ulTotalDataLength; + + /* Determine how many bytes we need to receive. */ + ucBytesToGet = + pxControlRx.ulTotalDataLength - pxControlRx.ulNextCharIndex; + if (ucBytesToGet > ulRxBytes) + { + ucBytesToGet = ulRxBytes; + } + + /* If we're not expecting any data, it's an ack - just quit now. */ + if (!ucBytesToGet) + { + return; + } + + /* Get the required data and update the index. */ + memcpy (pxControlRx.ucBuffer, pxMessage->ucFifoData, ucBytesToGet); + pxControlRx.ulNextCharIndex += ucBytesToGet; + } + + if (pxMessage->ulCSR0 & AT91C_UDP_RXSETUP) + { + /* Received a SETUP packet. May be followed by data packets. */ + + if (ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES) + { + /* Create an xUSB_REQUEST variable from the raw bytes array. */ + + xRequest.ucReqType = pxMessage->ucFifoData[usbREQUEST_TYPE_INDEX]; + xRequest.ucRequest = pxMessage->ucFifoData[usbREQUEST_INDEX]; + + xRequest.usValue = pxMessage->ucFifoData[usbVALUE_HIGH_BYTE]; + xRequest.usValue <<= 8; + xRequest.usValue |= pxMessage->ucFifoData[usbVALUE_LOW_BYTE]; + + xRequest.usIndex = pxMessage->ucFifoData[usbINDEX_HIGH_BYTE]; + xRequest.usIndex <<= 8; + xRequest.usIndex |= pxMessage->ucFifoData[usbINDEX_LOW_BYTE]; + + xRequest.usLength = pxMessage->ucFifoData[usbLENGTH_HIGH_BYTE]; + xRequest.usLength <<= 8; + xRequest.usLength |= pxMessage->ucFifoData[usbLENGTH_LOW_BYTE]; + + pxControlRx.ulNextCharIndex = 0; + if (!(xRequest.ucReqType & 0x80)) /* Host-to-Device transfer, may need to get data first */ + { + if (xRequest.usLength > usbMAX_CONTROL_MESSAGE_SIZE) + { + /* Too big! No space for control data, stall and abort. */ + prvSendStall (); + return; + } + + pxControlRx.ulTotalDataLength = xRequest.usLength; + } + else + { + /* We're sending the data, don't wait for any. */ + pxControlRx.ulTotalDataLength = 0; + } + } + } + + /* See if we've got a pending request and all its associated data ready */ + if ((pxMessage->ulCSR0 & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP)) + && (pxControlRx.ulNextCharIndex >= pxControlRx.ulTotalDataLength)) + { + unsigned portCHAR ucRequest; + + /* Manipulate the ucRequestType and the ucRequest parameters to + generate a zero based request selection. This is just done to + break up the requests into subsections for clarity. The + alternative would be to have more huge switch statement that would + be difficult to optimise. */ + ucRequest = ((xRequest.ucReqType & 0x60) >> 3); + ucRequest |= (xRequest.ucReqType & 0x03); + + switch (ucRequest) + { + case usbSTANDARD_DEVICE_REQUEST: + /* Standard Device request */ + prvHandleStandardDeviceRequest (&xRequest); + break; + + case usbSTANDARD_INTERFACE_REQUEST: + /* Standard Interface request */ + prvHandleStandardInterfaceRequest (&xRequest); + break; + + case usbSTANDARD_END_POINT_REQUEST: + /* Standard Endpoint request */ + prvHandleStandardEndPointRequest (&xRequest); + break; + + case usbCLASS_INTERFACE_REQUEST: + /* Class Interface request */ + prvHandleClassInterfaceRequest (&xRequest); + break; + + default: /* This is not something we want to respond to. */ + prvSendStall (); + } + } +} + +/*------------------------------------------------------------*/ + +static void +prvGetStandardDeviceDescriptor (xUSB_REQUEST * pxRequest) +{ + /* The type is in the high byte. Return whatever has been requested. */ + switch ((pxRequest->usValue & 0xff00) >> 8) + { + case usbDESCRIPTOR_TYPE_DEVICE: + prvSendControlData ((unsigned portCHAR *) &pxDeviceDescriptor, + pxRequest->usLength, sizeof (pxDeviceDescriptor), + pdTRUE); + break; + + case usbDESCRIPTOR_TYPE_CONFIGURATION: + prvSendControlData ((unsigned portCHAR *) &(pxConfigDescriptor), + pxRequest->usLength, sizeof (pxConfigDescriptor), + pdTRUE); + break; + + case usbDESCRIPTOR_TYPE_STRING: + + /* The index to the string descriptor is the lower byte. */ + switch (pxRequest->usValue & 0xff) + { + case usbLANGUAGE_STRING: + prvSendControlData ((unsigned portCHAR *) + &pxLanguageStringDescriptor, + pxRequest->usLength, + sizeof (pxLanguageStringDescriptor), pdTRUE); + break; + + case usbMANUFACTURER_STRING: + prvSendControlData ((unsigned portCHAR *) + &pxManufacturerStringDescriptor, + pxRequest->usLength, + sizeof (pxManufacturerStringDescriptor), + pdTRUE); + break; + + case usbPRODUCT_STRING: + prvSendControlData ((unsigned portCHAR *) + &pxProductStringDescriptor, pxRequest->usLength, + sizeof (pxProductStringDescriptor), pdTRUE); + break; + + default: + prvSendStall (); + break; + } + break; + + default: + prvSendStall (); + break; + } +} + +/*------------------------------------------------------------*/ + +static void +prvHandleStandardDeviceRequest (xUSB_REQUEST * pxRequest) +{ + unsigned portSHORT usStatus = 0; + + switch (pxRequest->ucRequest) + { + case usbGET_STATUS_REQUEST: + /* Just send two byte dummy status. */ + prvSendControlData ((unsigned portCHAR *) &usStatus, sizeof (usStatus), + sizeof (usStatus), pdFALSE); + break; + + case usbGET_DESCRIPTOR_REQUEST: + /* Send device descriptor */ + prvGetStandardDeviceDescriptor (pxRequest); + break; + + case usbGET_CONFIGURATION_REQUEST: + /* Send selected device configuration */ + prvSendControlData ((unsigned portCHAR *) &ucUSBConfig, + sizeof (ucUSBConfig), sizeof (ucUSBConfig), + pdFALSE); + break; + + case usbSET_FEATURE_REQUEST: + prvSendZLP (); + break; + + case usbSET_ADDRESS_REQUEST: + /* Get assigned address and send ack, but don't implement new address until we get a TXCOMP */ + prvSendZLP (); + eDriverState = eJUST_GOT_ADDRESS; + ulReceivedAddress = (unsigned portLONG) pxRequest->usValue; + break; + + case usbSET_CONFIGURATION_REQUEST: + /* Ack SET_CONFIGURATION request, but don't implement until TXCOMP */ + ucUSBConfig = (unsigned portCHAR) (pxRequest->usValue & 0xff); + eDriverState = eJUST_GOT_CONFIG; + prvSendZLP (); + break; + + default: + /* Any unsupported request results in a STALL response. */ + prvSendStall (); + break; + } +} + +/*------------------------------------------------------------*/ + +static void +prvHandleClassInterfaceRequest (xUSB_REQUEST * pxRequest) +{ + switch (pxRequest->ucRequest) + { + case usbSEND_ENCAPSULATED_COMMAND: + prvSendStall (); + break; + + case usbGET_ENCAPSULATED_RESPONSE: + prvSendStall (); + break; + + case usbSET_LINE_CODING: + /* Set line coding - baud rate, data bits, parity, stop bits */ + prvSendZLP (); + memcpy ((void *) pxLineCoding, pxControlRx.ucBuffer, + sizeof (pxLineCoding)); + break; + + case usbGET_LINE_CODING: + /* Get line coding */ + prvSendControlData ((unsigned portCHAR *) &pxLineCoding, + pxRequest->usLength, sizeof (pxLineCoding), + pdFALSE); + break; + + case usbSET_CONTROL_LINE_STATE: + /* D0: 1=DTR, 0=No DTR, D1: 1=Activate Carrier, 0=Deactivate carrier (RTS, half-duplex) */ + prvSendZLP (); + ucControlState = pxRequest->usValue; + break; + + default: + prvSendStall (); + break; + } +} + +/*------------------------------------------------------------*/ + +static void +prvGetStandardInterfaceDescriptor (xUSB_REQUEST * pxRequest) +{ + switch ((pxRequest->usValue & (unsigned portSHORT) 0xff00) >> 8) + { + default: + prvSendStall (); + break; + } +} + +/*-----------------------------------------------------------*/ + +static void +prvHandleStandardInterfaceRequest (xUSB_REQUEST * pxRequest) +{ + unsigned portSHORT usStatus = 0; + + switch (pxRequest->ucRequest) + { + case usbGET_STATUS_REQUEST: + /* Send dummy 2 bytes. */ + prvSendControlData ((unsigned portCHAR *) &usStatus, sizeof (usStatus), + sizeof (usStatus), pdFALSE); + break; + + case usbGET_DESCRIPTOR_REQUEST: + prvGetStandardInterfaceDescriptor (pxRequest); + break; + + /* This minimal implementation does not respond to these. */ + case usbGET_INTERFACE_REQUEST: + case usbSET_FEATURE_REQUEST: + case usbSET_INTERFACE_REQUEST: + + default: + prvSendStall (); + break; + } +} + +/*-----------------------------------------------------------*/ + +static void +prvHandleStandardEndPointRequest (xUSB_REQUEST * pxRequest) +{ + switch (pxRequest->ucRequest) + { + /* This minimal implementation does not expect to respond to these. */ + case usbGET_STATUS_REQUEST: + case usbCLEAR_FEATURE_REQUEST: + case usbSET_FEATURE_REQUEST: + + default: + prvSendStall (); + break; + } +} + +/*-----------------------------------------------------------*/ + +static void +vDetachUSBInterface (void) +{ + /* Setup the PIO for the USB pull up resistor. */ + AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16; + AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16; + + + /* Disable pull up */ + AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16; +} + +/*-----------------------------------------------------------*/ + +static void +vInitUSBInterface (void) +{ + extern void (vUSB_ISR) (void); + + /* Create the queue used to communicate between the USB ISR and task. */ + xUSBInterruptQueue = + xQueueCreate (usbQUEUE_LENGTH + 1, sizeof (xISRStatus *)); + + /* Create the queues used to hold Rx and Tx characters. */ + xRxCDC = + xQueueCreate (USB_CDC_QUEUE_SIZE, + (unsigned portCHAR) sizeof (signed portCHAR)); + xTxCDC = + xQueueCreate (USB_CDC_QUEUE_SIZE + 1, + (unsigned portCHAR) sizeof (signed portCHAR)); + + if ((!xUSBInterruptQueue) || (!xRxCDC) || (!xTxCDC)) + { + /* Not enough RAM to create queues!. */ + return; + } + + /* Initialise a few state variables. */ + pxControlTx.ulNextCharIndex = (unsigned portLONG) 0; + pxControlRx.ulNextCharIndex = (unsigned portLONG) 0; + ucUSBConfig = (unsigned portCHAR) 0; + eDriverState = eNOTHING; + ucControlState = 0; + uiCurrentBank = AT91C_UDP_RX_DATA_BK0; + + + /* HARDWARE SETUP */ + + /* Set the PLL USB Divider */ + AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1; + + /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */ + AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP; + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP); + + /* Setup the PIO for the USB pull up resistor. */ + AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA16; + AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA16; + + + /* Start without the pullup - this will get set at the end of this + function. */ + AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA16; + + + /* When using the USB debugger the peripheral registers do not always get + set to the correct default values. To make sure set the relevant registers + manually here. */ + AT91C_BASE_UDP->UDP_IDR = (unsigned portLONG) 0xffffffff; + AT91C_BASE_UDP->UDP_ICR = (unsigned portLONG) 0xffffffff; + AT91C_BASE_UDP->UDP_CSR[0] = (unsigned portLONG) 0x00; + AT91C_BASE_UDP->UDP_CSR[1] = (unsigned portLONG) 0x00; + AT91C_BASE_UDP->UDP_CSR[2] = (unsigned portLONG) 0x00; + AT91C_BASE_UDP->UDP_CSR[3] = (unsigned portLONG) 0x00; + AT91C_BASE_UDP->UDP_GLBSTATE = 0; + AT91C_BASE_UDP->UDP_FADDR = 0; + + /* Enable the transceiver. */ + AT91C_UDP_TRANSCEIVER_ENABLE = 0; + + /* Enable the USB interrupts - other interrupts get enabled as the + enumeration process progresses. */ + AT91F_AIC_ConfigureIt (AT91C_ID_UDP, usbINTERRUPT_PRIORITY, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, + (void (*)(void)) vUSB_ISR); + AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP; + + + /* Wait a short while before making our presence known. */ + vTaskDelay (usbINIT_DELAY); + AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA16; +} + +/*-----------------------------------------------------------*/ + +static void +prvSendControlData (unsigned portCHAR * pucData, + unsigned portSHORT usRequestedLength, + unsigned portLONG ulLengthToSend, + portLONG lSendingDescriptor) +{ + if (((unsigned portLONG) usRequestedLength < ulLengthToSend)) + { + /* Cap the data length to that requested. */ + ulLengthToSend = (unsigned portSHORT) usRequestedLength; + } + else if ((ulLengthToSend < (unsigned portLONG) usRequestedLength) + && lSendingDescriptor) + { + /* We are sending a descriptor. If the descriptor is an exact + multiple of the FIFO length then it will have to be terminated + with a NULL packet. Set the state to indicate this if + necessary. */ + if ((ulLengthToSend % usbFIFO_LENGTH) == 0) + { + eDriverState = eSENDING_EVEN_DESCRIPTOR; + } + } + + /* Here we assume that the previous message has been sent. THERE IS NO + BUFFER OVERFLOW PROTECTION HERE. + + Copy the data to send into the buffer as we cannot send it all at once + (if it is greater than 8 bytes in length). */ + memcpy (pxControlTx.ucBuffer, pucData, ulLengthToSend); + + /* Reinitialise the buffer index so we start sending from the start of + the data. */ + pxControlTx.ulTotalDataLength = ulLengthToSend; + pxControlTx.ulNextCharIndex = (unsigned portLONG) 0; + + /* Send the first 8 bytes now. The rest will get sent in response to + TXCOMP interrupts. */ + prvSendNextSegment (); +} + +/*-----------------------------------------------------------*/ + +static void +prvSendNextSegment (void) +{ + volatile unsigned portLONG ulNextLength, ulStatus, ulLengthLeftToSend; + + /* Is there any data to send? */ + if (pxControlTx.ulTotalDataLength > pxControlTx.ulNextCharIndex) + { + ulLengthLeftToSend = + pxControlTx.ulTotalDataLength - pxControlTx.ulNextCharIndex; + + /* We can only send 8 bytes to the fifo at a time. */ + if (ulLengthLeftToSend > usbFIFO_LENGTH) + { + ulNextLength = usbFIFO_LENGTH; + } + else + { + ulNextLength = ulLengthLeftToSend; + } + + /* Wait until we can place data in the fifo. THERE IS NO TIMEOUT + HERE! */ + while (AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] & AT91C_UDP_TXPKTRDY) + { + vTaskDelay (usbSHORTEST_DELAY); + } + + /* Write the data to the FIFO. */ + while (ulNextLength > (unsigned portLONG) 0) + { + AT91C_BASE_UDP->UDP_FDR[usbEND_POINT_0] = + pxControlTx.ucBuffer[pxControlTx.ulNextCharIndex]; + + ulNextLength--; + pxControlTx.ulNextCharIndex++; + } + + /* Start the transmission. */ + portENTER_CRITICAL (); + { + ulStatus = AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0]; + usbCSR_SET_BIT (&ulStatus, ((unsigned portLONG) 0x10)); + AT91C_BASE_UDP->UDP_CSR[usbEND_POINT_0] = ulStatus; + } + portEXIT_CRITICAL (); + } + else + { + /* There is no data to send. If we were sending a descriptor and the + descriptor was an exact multiple of the max packet size then we need + to send a null to terminate the transmission. */ + if (eDriverState == eSENDING_EVEN_DESCRIPTOR) + { + prvSendZLP (); + eDriverState = eNOTHING; + } + } +} diff --git a/openpicc/os/usb/USB-CDC.h b/openpicc/os/usb/USB-CDC.h new file mode 100644 index 0000000..894ebfb --- /dev/null +++ b/openpicc/os/usb/USB-CDC.h @@ -0,0 +1,87 @@ +/* + 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. + + Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along + with commercial development and support options. + *************************************************************************** +*/ + +#ifndef USB_CDC_H +#define USB_CDC_H + +#include "usb.h" + +#define USB_CDC_QUEUE_SIZE 1024 + +/* Structure used to take a snapshot of the USB status from within the ISR. */ +typedef struct X_ISR_STATUS +{ + unsigned portLONG ulISR; + unsigned portLONG ulCSR0; + unsigned portCHAR ucFifoData[8]; +} xISRStatus; + +/* Structure used to hold the received requests. */ +typedef struct +{ + unsigned portCHAR ucReqType; + unsigned portCHAR ucRequest; + unsigned portSHORT usValue; + unsigned portSHORT usIndex; + unsigned portSHORT usLength; +} xUSB_REQUEST; + +typedef enum +{ + eNOTHING, + eJUST_RESET, + eJUST_GOT_CONFIG, + eJUST_GOT_ADDRESS, + eSENDING_EVEN_DESCRIPTOR, + eREADY_TO_SEND +} eDRIVER_STATE; + +/* Structure used to control the data being sent to the host. */ +typedef struct +{ + unsigned portCHAR ucBuffer[usbMAX_CONTROL_MESSAGE_SIZE]; + unsigned portLONG ulNextCharIndex; + unsigned portLONG ulTotalDataLength; +} xCONTROL_MESSAGE; + +/*-----------------------------------------------------------*/ +void vUSBCDCTask (void *pvParameters); + +/* Send cByte down the USB port. Characters are simply buffered and not +sent unless the port is connected. */ +void vUSBSendByte (portCHAR cByte); +portLONG vUSBRecvByte (portCHAR *cByte,portLONG size, portTickType xTicksToWait); + +#endif 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)} diff --git a/openpicc/os/usb/descriptors.h b/openpicc/os/usb/descriptors.h new file mode 100644 index 0000000..230122f --- /dev/null +++ b/openpicc/os/usb/descriptors.h @@ -0,0 +1,190 @@ +/* + 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. + + Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along + with commercial development and support options. + *************************************************************************** +*/ + +/* + - DESCRIPTOR DEFINITIONS - +*/ + +/* String descriptors used during the enumeration process. +These take the form: + +{ + Length of descriptor, + Descriptor type, + Data +} +*/ + +const portCHAR pxLanguageStringDescriptor[] = { + 4, + usbDESCRIPTOR_TYPE_STRING, + 0x09, 0x04 +}; + +const portCHAR pxManufacturerStringDescriptor[] = { + 28, + usbDESCRIPTOR_TYPE_STRING, + + 'b', 0x00, 'i', 0x00, 't', 0x00, 'm', 0x00, + 'a', 0x00, 'n', 0x00, 'u', 0x00, 'f', 0x00, + 'a', 0x00, 'k', 0x00, 't', 0x00, 'u', 0x00, + 'r', 0x00 +}; + +const portCHAR pxProductStringDescriptor[] = { + 44, + usbDESCRIPTOR_TYPE_STRING, + + 'O', 0x00, 'p', 0x00, 'e', 0x00, 'n', 0x00, + 'B', 0x00, 'e', 0x00, 'a', 0x00, 'c', 0x00, + 'o', 0x00, 'n', 0x00, ' ', 0x00, 'U', 0x00, + 'S', 0x00, 'B', 0x00, ' ', 0x00, '2', 0x00, + '.', 0x00, '4', 0x00, 'G', 0x00, 'H', 0x00, + 'z', 0x00 +}; + +/* Device should properly be 0x134A:0x9001, using 0x05F9:0xFFFF for Linux testing */ +const char pxDeviceDescriptor[] = { + /* Device descriptor */ + 0x12, /* bLength */ + 0x01, /* bDescriptorType */ + 0x10, 0x01, /* bcdUSBL */ + 0x02, /* bDeviceClass: */ + 0x00, /* bDeviceSubclass: */ + 0x00, /* bDeviceProtocol: */ + 0x08, /* bMaxPacketSize0 */ + 0xC0, 0x16, /* idVendorL */ + 0xAC, 0x08, /* idProductL */ + 0x10, 0x01, /* bcdDeviceL */ + usbMANUFACTURER_STRING, /* iManufacturer */ + usbPRODUCT_STRING, /* iProduct */ + 0x00, /* SerialNumber */ + 0x01 /* bNumConfigs */ +}; + +const char pxConfigDescriptor[] = { + + /* Configuration 1 descriptor + Here we define two interfaces (0 and 1) and a total of 3 endpoints. + Interface 0 is a CDC Abstract Control Model interface with one interrupt-in endpoint. + Interface 1 is a CDC Data Interface class, with a bulk-in and bulk-out endpoint. + Endpoint 0 gets used as the CDC management element. + */ + 0x09, /* CbLength */ + 0x02, /* CbDescriptorType */ + 0x43, 0x00, /* CwTotalLength 2 EP + Control ? */ + 0x02, /* CbNumInterfaces */ + 0x01, /* CbConfigurationValue */ + 0x00, /* CiConfiguration */ + usbBUS_POWERED, /* CbmAttributes Bus powered + Remote Wakeup */ + 0x32, /* CMaxPower: 100mA */ + + /* Communication Class Interface Descriptor Requirement */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + 0x02, /* bInterfaceClass: Comm Interface Class */ + 0x02, /* bInterfaceSubclass: Abstract Control Model */ + 0x01, /* bInterfaceProtocol */ + usbINTERFACE_STRING, /* iInterface */ + + /* Header Functional Descriptor */ + 0x05, /* bLength */ + 0x24, /* bDescriptor type: CS_INTERFACE */ + 0x00, /* bDescriptor subtype: Header Func Desc */ + 0x10, 0x01, /* bcdCDC:1.1 */ + + /* ACM Functional Descriptor */ + 0x04, /* bFunctionLength */ + 0x24, /* bDescriptor type: CS_INTERFACE */ + 0x02, /* bDescriptor subtype: ACM Func Desc */ + 0x00, /* bmCapabilities: We don't support squat */ + + /* Union Functional Descriptor */ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptor type: CS_INTERFACE */ + 0x06, /* bDescriptor subtype: Union Func Desc */ + 0x00, /* bMasterInterface: CDC Interface */ + 0x01, /* bSlaveInterface0: Data Class Interface */ + + /* Call Management Functional Descriptor + 0 in D1 and D0 indicates that device does not handle call management */ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptor type: CS_INTERFACE */ + 0x01, /* bDescriptor subtype: Call Management Func */ + 0x00, /* bmCapabilities: D1 + D0 */ + 0x01, /* bDataInterface: Data Class Interface 1 */ + + /* CDC Control - Endpoint 3 descriptor + This endpoint serves as a notification element. */ + + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x83, /* bEndpointAddress, Endpoint 03 - IN */ + 0x03, /* bmAttributes INT */ + 0x08, 0x00, /* wMaxPacketSize: 8 bytes */ + 0xFF, /* bInterval */ + + /* Data Class Interface Descriptor Requirement */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x02, /* bNumEndPoints */ + 0x0A, /* bInterfaceClass */ + 0x00, /* bInterfaceSubclass */ + 0x00, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + /* CDC Data - Endpoint 1 descriptor */ + 0x07, /* bLenght */ + 0x05, /* bDescriptorType */ + 0x01, /* bEndPointAddress, Endpoint 01 - OUT */ + 0x02, /* bmAttributes BULK */ + 64, /* wMaxPacketSize */ + 0x00, + 0x00, /* bInterval */ + + /* CDC Data - Endpoint 2 descriptor */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType */ + 0x82, /* bEndPointAddress, Endpoint 02 - IN */ + 0x02, /* bmAttributes BULK */ + 64, /* wMaxPacketSize */ + 0x00, + 0x00 /* bInterval */ +}; diff --git a/openpicc/os/usb/usb.h b/openpicc/os/usb/usb.h new file mode 100644 index 0000000..86d98f9 --- /dev/null +++ b/openpicc/os/usb/usb.h @@ -0,0 +1,146 @@ +/* + 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. + + Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along + with commercial development and support options. + *************************************************************************** +*/ + +/* Descriptor type definitions. */ +#define usbDESCRIPTOR_TYPE_DEVICE ( 0x01 ) +#define usbDESCRIPTOR_TYPE_CONFIGURATION ( 0x02 ) +#define usbDESCRIPTOR_TYPE_STRING ( 0x03 ) + +/* USB request type definitions. */ +#define usbGET_REPORT_REQUEST ( 0x01 ) +#define usbGET_IDLE_REQUEST ( 0x02 ) +#define usbGET_PROTOCOL_REQUEST ( 0x03 ) +#define usbSET_REPORT_REQUEST ( 0x09 ) +#define usbSET_IDLE_REQUEST ( 0x0A ) +#define usbSET_PROTOCOL_REQUEST ( 0x0B ) +#define usbGET_CONFIGURATION_REQUEST ( 0x08 ) +#define usbGET_STATUS_REQUEST ( 0x00 ) +#define usbCLEAR_FEATURE_REQUEST ( 0x01 ) +#define usbSET_FEATURE_REQUEST ( 0x03 ) +#define usbSET_ADDRESS_REQUEST ( 0x05 ) +#define usbGET_DESCRIPTOR_REQUEST ( 0x06 ) +#define usbSET_CONFIGURATION_REQUEST ( 0x09 ) +#define usbGET_INTERFACE_REQUEST ( 0x0A ) +#define usbSET_INTERFACE_REQUEST ( 0x0B ) + +/* ACM Requests */ +#define usbSEND_ENCAPSULATED_COMMAND ( 0x00 ) +#define usbGET_ENCAPSULATED_RESPONSE ( 0x01 ) +#define usbSET_LINE_CODING ( 0x20 ) +#define usbGET_LINE_CODING ( 0x21 ) +#define usbSET_CONTROL_LINE_STATE ( 0x22 ) + +/* Misc USB definitions. */ +#define usbDEVICE_CLASS_VENDOR_SPECIFIC ( 0xFF ) +#define usbBUS_POWERED ( 0x80 ) +#define usbHID_REPORT_DESCRIPTOR ( 0x22 ) +#define AT91C_UDP_TRANSCEIVER_ENABLE ( *( ( unsigned long * ) 0xfffb0074 ) ) + +/* Index to the various string. */ +#define usbLANGUAGE_STRING ( 0 ) +#define usbMANUFACTURER_STRING ( 1 ) +#define usbPRODUCT_STRING ( 2 ) +#define usbCONFIGURATION_STRING ( 3 ) +#define usbINTERFACE_STRING ( 4 ) + +/* Defines fields of standard SETUP request. Now in normal order. */ +#define usbREQUEST_TYPE_INDEX ( 0 ) +#define usbREQUEST_INDEX ( 1 ) +#define usbVALUE_HIGH_BYTE ( 3 ) +#define usbVALUE_LOW_BYTE ( 2 ) +#define usbINDEX_HIGH_BYTE ( 5 ) +#define usbINDEX_LOW_BYTE ( 4 ) +#define usbLENGTH_HIGH_BYTE ( 7 ) +#define usbLENGTH_LOW_BYTE ( 6 ) + +/* Misc application definitions. */ +#define usbINTERRUPT_PRIORITY ( 3 ) +#define usbQUEUE_LENGTH ( 0x3 ) /* Must have all bits set! */ +#define usbFIFO_LENGTH ( ( unsigned portLONG ) 8 ) +#define usbEND_POINT_0 ( 0 ) +#define usbEND_POINT_1 ( 1 ) +#define usbEND_POINT_2 ( 2 ) +#define usbEND_POINT_3 ( 3 ) +#define usbMAX_CONTROL_MESSAGE_SIZE ( 128 ) +#define usbRX_COUNT_MASK ( ( unsigned portLONG ) 0x7ff ) +#define usbSHORTEST_DELAY ( ( portTickType ) 1 ) +#define usbINIT_DELAY ( ( portTickType ) 1000 / portTICK_RATE_MS ) +#define usbSHORT_DELAY ( ( portTickType ) 50 / portTICK_RATE_MS ) +#define usbEND_POINT_RESET_MASK ( ( unsigned portLONG ) 0x0f ) +#define usbDATA_INC ( ( portCHAR ) 5 ) +#define usbEXPECTED_NUMBER_OF_BYTES ( ( unsigned portLONG ) 8 ) + +/* Control request types. */ +#define usbSTANDARD_DEVICE_REQUEST ( 0 ) +#define usbSTANDARD_INTERFACE_REQUEST ( 1 ) +#define usbSTANDARD_END_POINT_REQUEST ( 2 ) +#define usbCLASS_INTERFACE_REQUEST ( 5 ) + + +/* Macros to manipulate the control and status registers. These registers +cannot be accessed using a direct read modify write operation outside of the +ISR as some bits are left unchanged by writing with a 0, and some are left +unchanged by writing with a 1. */ + + +#define usbCSR_SET_BIT( pulValueNow, ulBit ) \ +{ \ + /* Set TXCOMP, RX_DATA_BK0, RXSETUP, */ \ + /* STALLSENT and RX_DATA_BK1 to 1 so the */ \ + /* write has no effect. */ \ + ( * ( ( unsigned portLONG * ) pulValueNow ) ) |= ( unsigned portLONG ) 0x4f; \ + \ + /* Clear the FORCE_STALL and TXPKTRDY bits */ \ + /* so the write has no effect. */ \ + ( * ( ( unsigned portLONG * ) pulValueNow ) ) &= ( unsigned portLONG ) 0xffffffcf; \ + \ + /* Set whichever bit we want set. */ \ + ( * ( ( unsigned portLONG * ) pulValueNow ) ) |= ( ulBit ); \ +} + +#define usbCSR_CLEAR_BIT( pulValueNow, ulBit ) \ +{ \ + /* Set TXCOMP, RX_DATA_BK0, RXSETUP, */ \ + /* STALLSENT and RX_DATA_BK1 to 1 so the */ \ + /* write has no effect. */ \ + ( * ( ( unsigned portLONG * ) pulValueNow ) ) |= ( unsigned portLONG ) 0x4f; \ + \ + /* Clear the FORCE_STALL and TXPKTRDY bits */ \ + /* so the write has no effect. */ \ + ( * ( ( unsigned portLONG * ) pulValueNow ) ) &= ( unsigned portLONG ) 0xffffffcf; \ + \ + /* Clear whichever bit we want clear. */ \ + ( * ( ( unsigned portLONG * ) pulValueNow ) ) &= ( ~ulBit ); \ +} |