00001 /* 00002 FreeRTOS.org V4.6.0 - Copyright (C) 2003-2007 Richard Barry. 00003 00004 This file is part of the FreeRTOS.org distribution. 00005 00006 FreeRTOS.org is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 2 of the License, or 00009 (at your option) any later version. 00010 00011 FreeRTOS.org is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with FreeRTOS.org; if not, write to the Free Software 00018 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 00020 A special exception to the GPL can be applied should you wish to distribute 00021 a combined work that includes FreeRTOS.org, without being obliged to provide 00022 the source code for any proprietary components. See the licensing section 00023 of http://www.FreeRTOS.org for full details of how and when the exception 00024 can be applied. 00025 00026 *************************************************************************** 00027 See http://www.FreeRTOS.org for documentation, latest information, license 00028 and contact details. Please ensure to read the configuration and relevant 00029 port sections of the online documentation. 00030 00031 Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along 00032 with commercial development and support options. 00033 *************************************************************************** 00034 */ 00035 00036 /* 00037 USB Communications Device Class driver. 00038 Implements task vUSBCDCTask and provides an Abstract Control Model serial 00039 interface. Control is through endpoint 0, device-to-host notification is 00040 provided by interrupt-in endpoint 3, and raw data is transferred through 00041 bulk endpoints 1 and 2. 00042 00043 - developed from original FreeRTOS HID example by Scott Miller 00044 - modified to support 3.2 GCC by najay 00045 */ 00046 00047 /* MakingThings */ 00048 #include "config.h" 00049 #ifdef MAKE_CTRL_USB 00050 00051 #include <string.h> 00052 #include <stdio.h> 00053 #include "Board.h" 00054 #include "FreeRTOS.h" 00055 #include "task.h" 00056 #include "queue.h" 00057 #include "USB-CDC.h" 00058 #include "descriptors.h" 00059 00060 #define usbNO_BLOCK ( ( portTickType ) 0 ) 00061 00062 /* Reset all endpoints */ 00063 static void prvResetEndPoints( void ); 00064 00065 /* Clear pull up resistor to detach device from host */ 00066 static void vDetachUSBInterface( void ); 00067 00068 /* Set up interface and initialize variables */ 00069 static void vInitUSBInterface( void ); 00070 00071 /* Handle control endpoint events. */ 00072 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage ); 00073 00074 /* Handle standard device requests. */ 00075 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest ); 00076 00077 /* Handle standard interface requests. */ 00078 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest ); 00079 00080 /* Handle endpoint requests. */ 00081 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest ); 00082 00083 /* Handle class interface requests. */ 00084 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest ); 00085 00086 /* Prepare control data transfer. prvSendNextSegment starts transfer. */ 00087 static void prvSendControlData( unsigned portCHAR *pucData, unsigned portSHORT usRequestedLength, unsigned portLONG ulLengthLeftToSend, portLONG lSendingDescriptor ); 00088 00089 /* Send next segment of data for the control transfer */ 00090 static void prvSendNextSegment( void ); 00091 00092 /* Send stall - used to respond to unsupported requests */ 00093 static void prvSendStall( void ); 00094 00095 /* Send a zero-length (null) packet */ 00096 static void prvSendZLP( int endpoint ); 00097 00098 /* Handle requests for standard interface descriptors */ 00099 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest ); 00100 00101 /*------------------------------------------------------------*/ 00102 00103 /* File scope static variables */ 00104 static unsigned portCHAR ucUSBConfig = ( unsigned portCHAR ) 0; 00105 static unsigned portLONG ulReceivedAddress = ( unsigned portLONG ) 0; 00106 static eDRIVER_STATE eDriverState = eNOTHING; 00107 00108 /* Incoming and outgoing control data structures */ 00109 static xCONTROL_MESSAGE pxControlTx; 00110 static xCONTROL_MESSAGE pxControlRx; 00111 00112 /* Queue holding pointers to pending messages */ 00113 xQueueHandle xUSBInterruptQueue; 00114 00115 /* Queues used to hold received characters, and characters waiting to be 00116 transmitted. Rx queue must be larger than FIFO size. */ 00117 xQueueHandle xRxCDC; 00118 xQueueHandle xTxCDC; 00119 00120 /* Line coding - 115,200 baud, N-8-1 */ 00121 static const unsigned portCHAR pxLineCoding[] = { 0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08 }; 00122 00123 /* Status variables. */ 00124 static unsigned portCHAR ucControlState; 00125 static unsigned int uiCurrentBank; 00126 00127 /*------------------------------------------------------------*/ 00128 extern int OscBusy; 00129 extern int Usb_Running; 00130 00131 void vUSBCDCTask( void *pvParameters ) 00132 { 00133 xISRStatus *pxMessage; 00134 unsigned portLONG ulStatus; 00135 unsigned portLONG ulRxBytes; 00136 00137 ( void ) pvParameters; 00138 00139 /* Disconnect USB device from hub. For debugging - causes host to register reset */ 00140 portENTER_CRITICAL(); 00141 vDetachUSBInterface(); 00142 portEXIT_CRITICAL(); 00143 00144 vTaskDelay( portTICK_RATE_MS * 60 ); 00145 00146 /* Init USB interface */ 00147 portENTER_CRITICAL(); 00148 vInitUSBInterface(); 00149 portEXIT_CRITICAL(); 00150 00151 /* Main task loop. Process incoming endpoint 0 interrupts, handle data transfers. */ 00152 00153 /* MAKINGTHINGS: USB RUNNING */ 00154 Usb_Running = 1; 00155 /* MakingThings - if we sent a packet that was a multiple of EP_FIFO, 00156 we need to send a zero length packet to force the transfer 00157 */ 00158 bool sentEvenPacket = false; 00159 00160 for( ;; ) 00161 { 00162 /* Look for data coming from the ISR. */ 00163 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORTEST_DELAY ) ) 00164 { 00165 if( pxMessage->ulISR & AT91C_UDP_EPINT0 ) 00166 { 00167 /* All endpoint 0 interrupts are handled here. */ 00168 prvProcessEndPoint0Interrupt( pxMessage ); 00169 } 00170 00171 if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES ) 00172 { 00173 /* End of bus reset - reset the endpoints and de-configure. */ 00174 prvResetEndPoints(); 00175 } 00176 } 00177 00178 if(sentEvenPacket) // if we sent a packet with a length multiple of EP_FIFO 00179 { 00180 prvSendZLP(usbEND_POINT_2); 00181 sentEvenPacket = false; 00182 } 00183 00184 /* See if we're ready to send and receive data. */ 00185 if( eDriverState == eREADY_TO_SEND && ucControlState ) 00186 { 00187 if( ( !(AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] & AT91C_UDP_TXPKTRDY) ) && uxQueueMessagesWaiting( xTxCDC ) ) 00188 { 00189 xBULKBUFFER Queue2USB; 00190 if( xQueueReceive( xTxCDC, &Queue2USB, 0 ) ) 00191 { 00192 unsigned char out = 0; 00193 sentEvenPacket = ( Queue2USB.Count == EP_FIFO); 00194 00195 while (out < Queue2USB.Count) 00196 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_2 ] = Queue2USB.Data[out++]; 00197 } 00198 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] |= AT91C_UDP_TXPKTRDY; 00199 } 00200 00201 /* Check for incoming data (host-to-device) on endpoint 1. */ 00202 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1) ) 00203 { 00204 /* Only process FIFO if there's room to store it in the queue */ 00205 if ( USB_CDC_QUEUE_SIZE > uxQueueMessagesWaiting( xRxCDC )) 00206 { 00207 xBULKBUFFER USB2Queue; 00208 00209 ulRxBytes = (AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] >> 16) & usbRX_COUNT_MASK; 00210 // collect however many bytes are in endpoint ... may be a whole osc packet 00211 // may just be a fragment. 00212 USB2Queue.Count = 0; 00213 while( ulRxBytes-- ) 00214 USB2Queue.Data[USB2Queue.Count++] = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ]; 00215 00216 // put it in the queue 00217 xQueueSend( xRxCDC, &USB2Queue, 0 ); 00218 00219 /* Release the FIFO */ 00220 portENTER_CRITICAL(); 00221 { 00222 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ]; 00223 usbCSR_CLEAR_BIT( &ulStatus, uiCurrentBank ); 00224 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus; 00225 } 00226 portEXIT_CRITICAL(); 00227 00228 /* Re-enable endpoint 1's interrupts */ 00229 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1; 00230 00231 /* Update the current bank in use */ 00232 if( uiCurrentBank == AT91C_UDP_RX_DATA_BK0 ) 00233 uiCurrentBank = AT91C_UDP_RX_DATA_BK1; 00234 else 00235 uiCurrentBank = AT91C_UDP_RX_DATA_BK0; 00236 00237 } 00238 else 00239 break; 00240 } 00241 } 00242 } 00243 } 00244 /*------------------------------------------------------------*/ 00245 #if 0 00246 void vUSBSendByte( portCHAR cByte, int timeout ) 00247 { 00248 static xBULKBUFFER EnQueue; 00249 static char inPacket = 0; // OSC packet detection eliminates need for tx timeouts 00250 00251 if (!inPacket && (cByte == SOP)) 00252 { 00253 inPacket = 1; 00254 EnQueue.Count = 0; 00255 EnQueue.Data[EnQueue.Count++] = cByte; 00256 } 00257 else // in a packet 00258 { 00259 EnQueue.Data[EnQueue.Count++] = cByte; 00260 00261 // if end of packet of buffer full, commit buffer to queue 00262 if ((cByte == SOP) || (EnQueue.Count == EP_FIFO)) 00263 { 00264 if (cByte == SOP) inPacket = 0; 00265 // if ( xQueueSend( xTxCDC, &EnQueue, timeout ) != pdPASS ) 00266 while (xQueueSend( xTxCDC, &EnQueue, 0 ) != pdPASS ) 00267 ; 00268 00269 EnQueue.Count = 0; 00270 } 00271 } 00272 } 00273 #endif 00274 00275 #if 0 00276 inline int cUSBGetByte( portTickType timeout ) 00277 { 00278 static xBULKBUFFER DeQueue; 00279 static char QueueValid = 0; 00280 static unsigned char out; 00281 00282 // first look for bytes in a buffer we've already gotten 00283 drainQueue: 00284 if (QueueValid) { 00285 if (out < DeQueue.Count) 00286 return DeQueue.Data[out++]; // drain the buffer 00287 else 00288 QueueValid = 0; // buffer was empty ... next check for new one. 00289 } 00290 00291 if ( xQueueReceive( xRxCDC, &DeQueue, timeout ) != pdFAIL ) 00292 { 00293 // got a new message from USB waiting on the queue 00294 out = 0; // reset drain index 00295 QueueValid = 1; // indicate we'll be working from the just copied message 00296 goto drainQueue; // now go back and fetch the first entry from message 00297 } 00298 else 00299 return -1; // nope, there was really nothing available 00300 } 00301 #endif 00302 /*------------------------------------------------------------*/ 00303 00304 static void prvSendZLP( int endpoint ) 00305 { 00306 unsigned portLONG ulStatus; 00307 00308 /* Wait until the FIFO is free - even though we are not going to use it. 00309 THERE IS NO TIMEOUT HERE! */ 00310 while( AT91C_BASE_UDP->UDP_CSR[ endpoint ] & AT91C_UDP_TXPKTRDY ) 00311 { 00312 vTaskDelay( usbSHORTEST_DELAY ); 00313 } 00314 00315 portENTER_CRITICAL(); 00316 { 00317 /* Cancel any further pending data */ 00318 pxControlTx.ulTotalDataLength = pxControlTx.ulNextCharIndex; 00319 00320 /* Set the TXPKTRDY bit to cause a transmission with no data. */ 00321 ulStatus = AT91C_BASE_UDP->UDP_CSR[ endpoint ]; 00322 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_TXPKTRDY ); 00323 AT91C_BASE_UDP->UDP_CSR[ endpoint ] = ulStatus; 00324 } 00325 portEXIT_CRITICAL(); 00326 } 00327 /*------------------------------------------------------------*/ 00328 00329 static void prvSendStall( void ) 00330 { 00331 unsigned portLONG ulStatus; 00332 00333 portENTER_CRITICAL(); 00334 { 00335 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */ 00336 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ]; 00337 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL ); 00338 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus; 00339 } 00340 portEXIT_CRITICAL(); 00341 } 00342 /*------------------------------------------------------------*/ 00343 00344 static void prvResetEndPoints( void ) 00345 { 00346 unsigned portLONG ulTemp; 00347 00348 eDriverState = eJUST_RESET; 00349 ucControlState = 0; 00350 00351 /* Reset all the end points. */ 00352 AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK; 00353 AT91C_BASE_UDP->UDP_RSTEP = ( unsigned portLONG ) 0x00; 00354 00355 /* Enable data to be sent and received. */ 00356 AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN; 00357 00358 /* Repair the configuration end point. */ 00359 portENTER_CRITICAL(); 00360 { 00361 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ]; 00362 usbCSR_SET_BIT( &ulTemp, ( ( unsigned portLONG ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) ); 00363 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp; 00364 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0; 00365 } 00366 portEXIT_CRITICAL(); 00367 uiCurrentBank = AT91C_UDP_RX_DATA_BK0; 00368 } 00369 /*------------------------------------------------------------*/ 00370 00371 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage ) 00372 { 00373 static xUSB_REQUEST xRequest; 00374 unsigned portLONG ulRxBytes; 00375 00376 /* Get number of bytes received, if any */ 00377 ulRxBytes = pxMessage->ulCSR0 >> 16; 00378 ulRxBytes &= usbRX_COUNT_MASK; 00379 00380 if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP ) 00381 { 00382 /* We received a TX complete interrupt. What we do depends on 00383 what we sent to get this interrupt. */ 00384 00385 if( eDriverState == eJUST_GOT_CONFIG ) 00386 { 00387 /* We sent an acknowledgement of a SET_CONFIG request. We 00388 are now at the end of the enumeration. 00389 00390 TODO: Config 0 sets unconfigured state, should enter Address state. 00391 Request for unsupported config should stall. */ 00392 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG; 00393 00394 /* Set up endpoints */ 00395 portENTER_CRITICAL(); 00396 { 00397 unsigned portLONG ulTemp; 00398 00399 /* Set endpoint 1 to bulk-out */ 00400 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ]; 00401 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT ); 00402 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp; 00403 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT1; 00404 /* Set endpoint 2 to bulk-in */ 00405 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ]; 00406 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN ); 00407 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_2 ] = ulTemp; 00408 AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT2; 00409 /* Set endpoint 3 to interrupt-in, enable it, and enable interrupts */ 00410 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ]; 00411 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN ); 00412 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_3 ] = ulTemp; 00413 /*AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT3 ); */ 00414 } 00415 portEXIT_CRITICAL(); 00416 00417 eDriverState = eREADY_TO_SEND; 00418 } 00419 else if( eDriverState == eJUST_GOT_ADDRESS ) 00420 { 00421 /* We sent an acknowledgement of a SET_ADDRESS request. Move 00422 to the addressed state. */ 00423 if( ulReceivedAddress != ( unsigned portLONG ) 0 ) 00424 { 00425 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN; 00426 } 00427 else 00428 { 00429 AT91C_BASE_UDP->UDP_GLBSTATE = 0; 00430 } 00431 00432 AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress ); 00433 eDriverState = eNOTHING; 00434 } 00435 else 00436 { 00437 /* The TXCOMP was not for any special type of transmission. See 00438 if there is any more data to send. */ 00439 prvSendNextSegment(); 00440 } 00441 } 00442 00443 if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 ) 00444 { 00445 /* Received a control data packet. May be a 0-length ACK or a data stage. */ 00446 unsigned portCHAR ucBytesToGet; 00447 00448 /* Got data. Cancel any outgoing data. */ 00449 pxControlTx.ulNextCharIndex = pxControlTx.ulTotalDataLength; 00450 00451 /* Determine how many bytes we need to receive. */ 00452 ucBytesToGet = pxControlRx.ulTotalDataLength - pxControlRx.ulNextCharIndex; 00453 if( ucBytesToGet > ulRxBytes ) 00454 { 00455 ucBytesToGet = ulRxBytes; 00456 } 00457 00458 /* If we're not expecting any data, it's an ack - just quit now. */ 00459 if( !ucBytesToGet ) 00460 { 00461 return; 00462 } 00463 00464 /* Get the required data and update the index. */ 00465 memcpy( pxControlRx.ucBuffer, pxMessage->ucFifoData, ucBytesToGet ); 00466 pxControlRx.ulNextCharIndex += ucBytesToGet; 00467 } 00468 00469 if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP ) 00470 { 00471 /* Received a SETUP packet. May be followed by data packets. */ 00472 00473 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES ) 00474 { 00475 /* Create an xUSB_REQUEST variable from the raw bytes array. */ 00476 00477 xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ]; 00478 xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ]; 00479 00480 xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ]; 00481 xRequest.usValue <<= 8; 00482 xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ]; 00483 00484 xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ]; 00485 xRequest.usIndex <<= 8; 00486 xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ]; 00487 00488 xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ]; 00489 xRequest.usLength <<= 8; 00490 xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ]; 00491 00492 pxControlRx.ulNextCharIndex = 0; 00493 if( ! (xRequest.ucReqType & 0x80) ) /* Host-to-Device transfer, may need to get data first */ 00494 { 00495 if( xRequest.usLength > usbMAX_CONTROL_MESSAGE_SIZE ) 00496 { 00497 /* Too big! No space for control data, stall and abort. */ 00498 prvSendStall(); 00499 return; 00500 } 00501 00502 pxControlRx.ulTotalDataLength = xRequest.usLength; 00503 } 00504 else 00505 { 00506 /* We're sending the data, don't wait for any. */ 00507 pxControlRx.ulTotalDataLength = 0; 00508 } 00509 } 00510 } 00511 00512 /* See if we've got a pending request and all its associated data ready */ 00513 if( ( pxMessage->ulCSR0 & ( AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP ) ) 00514 && ( pxControlRx.ulNextCharIndex >= pxControlRx.ulTotalDataLength ) ) 00515 { 00516 unsigned portCHAR ucRequest; 00517 00518 /* Manipulate the ucRequestType and the ucRequest parameters to 00519 generate a zero based request selection. This is just done to 00520 break up the requests into subsections for clarity. The 00521 alternative would be to have more huge switch statement that would 00522 be difficult to optimise. */ 00523 ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 ); 00524 ucRequest |= ( xRequest.ucReqType & 0x03 ); 00525 00526 switch( ucRequest ) 00527 { 00528 case usbSTANDARD_DEVICE_REQUEST: 00529 /* Standard Device request */ 00530 prvHandleStandardDeviceRequest( &xRequest ); 00531 break; 00532 00533 case usbSTANDARD_INTERFACE_REQUEST: 00534 /* Standard Interface request */ 00535 prvHandleStandardInterfaceRequest( &xRequest ); 00536 break; 00537 00538 case usbSTANDARD_END_POINT_REQUEST: 00539 /* Standard Endpoint request */ 00540 prvHandleStandardEndPointRequest( &xRequest ); 00541 break; 00542 00543 case usbCLASS_INTERFACE_REQUEST: 00544 /* Class Interface request */ 00545 prvHandleClassInterfaceRequest( &xRequest ); 00546 break; 00547 00548 default: /* This is not something we want to respond to. */ 00549 prvSendStall(); 00550 } 00551 } 00552 } 00553 /*------------------------------------------------------------*/ 00554 00555 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest ) 00556 { 00557 /* The type is in the high byte. Return whatever has been requested. */ 00558 switch( ( pxRequest->usValue & 0xff00 ) >> 8 ) 00559 { 00560 case usbDESCRIPTOR_TYPE_DEVICE: 00561 prvSendControlData( ( unsigned portCHAR * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE ); 00562 break; 00563 00564 case usbDESCRIPTOR_TYPE_CONFIGURATION: 00565 prvSendControlData( ( unsigned portCHAR * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE ); 00566 break; 00567 00568 case usbDESCRIPTOR_TYPE_STRING: 00569 00570 /* The index to the string descriptor is the lower byte. */ 00571 switch( pxRequest->usValue & 0xff ) 00572 { 00573 case usbLANGUAGE_STRING: 00574 prvSendControlData( ( unsigned portCHAR * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE ); 00575 break; 00576 00577 case usbMANUFACTURER_STRING: 00578 prvSendControlData( ( unsigned portCHAR * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE ); 00579 break; 00580 00581 case usbPRODUCT_STRING: 00582 prvSendControlData( ( unsigned portCHAR * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE ); 00583 break; 00584 00585 case usbCONFIGURATION_STRING: 00586 prvSendControlData( ( unsigned portCHAR * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE ); 00587 break; 00588 00589 case usbINTERFACE_STRING: 00590 prvSendControlData( ( unsigned portCHAR * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE ); 00591 break; 00592 00593 default: 00594 prvSendStall(); 00595 break; 00596 } 00597 break; 00598 00599 default: 00600 prvSendStall(); 00601 break; 00602 } 00603 } 00604 /*------------------------------------------------------------*/ 00605 00606 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest ) 00607 { 00608 unsigned portSHORT usStatus = 0; 00609 00610 switch( pxRequest->ucRequest ) 00611 { 00612 case usbGET_STATUS_REQUEST: 00613 /* Just send two byte dummy status. */ 00614 prvSendControlData( ( unsigned portCHAR * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE ); 00615 break; 00616 00617 case usbGET_DESCRIPTOR_REQUEST: 00618 /* Send device descriptor */ 00619 prvGetStandardDeviceDescriptor( pxRequest ); 00620 break; 00621 00622 case usbGET_CONFIGURATION_REQUEST: 00623 /* Send selected device configuration */ 00624 prvSendControlData( ( unsigned portCHAR * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE ); 00625 break; 00626 00627 case usbSET_FEATURE_REQUEST: 00628 prvSendZLP(usbEND_POINT_0); 00629 break; 00630 00631 case usbSET_ADDRESS_REQUEST: 00632 /* Get assigned address and send ack, but don't implement new address until we get a TXCOMP */ 00633 prvSendZLP(usbEND_POINT_0); 00634 eDriverState = eJUST_GOT_ADDRESS; 00635 ulReceivedAddress = ( unsigned portLONG ) pxRequest->usValue; 00636 break; 00637 00638 case usbSET_CONFIGURATION_REQUEST: 00639 /* Ack SET_CONFIGURATION request, but don't implement until TXCOMP */ 00640 ucUSBConfig = ( unsigned portCHAR ) ( pxRequest->usValue & 0xff ); 00641 eDriverState = eJUST_GOT_CONFIG; 00642 prvSendZLP(usbEND_POINT_0); 00643 break; 00644 00645 default: 00646 /* Any unsupported request results in a STALL response. */ 00647 prvSendStall(); 00648 break; 00649 } 00650 } 00651 /*------------------------------------------------------------*/ 00652 00653 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest ) 00654 { 00655 switch( pxRequest->ucRequest ) 00656 { 00657 case usbSEND_ENCAPSULATED_COMMAND: 00658 prvSendStall(); 00659 break; 00660 00661 case usbGET_ENCAPSULATED_RESPONSE: 00662 prvSendStall(); 00663 break; 00664 00665 case usbSET_LINE_CODING: 00666 /* Set line coding - baud rate, data bits, parity, stop bits */ 00667 prvSendZLP(usbEND_POINT_0); 00668 memcpy( ( void * ) pxLineCoding, pxControlRx.ucBuffer, sizeof( pxLineCoding ) ); 00669 break; 00670 00671 case usbGET_LINE_CODING: 00672 /* Get line coding */ 00673 prvSendControlData( (unsigned portCHAR *) &pxLineCoding, pxRequest->usLength, sizeof( pxLineCoding ), pdFALSE ); 00674 break; 00675 00676 case usbSET_CONTROL_LINE_STATE: 00677 /* D0: 1=DTR, 0=No DTR, D1: 1=Activate Carrier, 0=Deactivate carrier (RTS, half-duplex) */ 00678 prvSendZLP(usbEND_POINT_0); 00679 ucControlState = pxRequest->usValue; 00680 break; 00681 00682 default: 00683 prvSendStall(); 00684 break; 00685 } 00686 } 00687 /*------------------------------------------------------------*/ 00688 00689 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest ) 00690 { 00691 switch( ( pxRequest->usValue & ( unsigned portSHORT ) 0xff00 ) >> 8 ) 00692 { 00693 default: 00694 prvSendStall(); 00695 break; 00696 } 00697 } 00698 /*-----------------------------------------------------------*/ 00699 00700 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest ) 00701 { 00702 unsigned portSHORT usStatus = 0; 00703 00704 switch( pxRequest->ucRequest ) 00705 { 00706 case usbGET_STATUS_REQUEST: 00707 /* Send dummy 2 bytes. */ 00708 prvSendControlData( ( unsigned portCHAR * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE ); 00709 break; 00710 00711 case usbGET_DESCRIPTOR_REQUEST: 00712 prvGetStandardInterfaceDescriptor( pxRequest ); 00713 break; 00714 00715 /* This minimal implementation does not respond to these. */ 00716 case usbGET_INTERFACE_REQUEST: 00717 case usbSET_FEATURE_REQUEST: 00718 case usbSET_INTERFACE_REQUEST: 00719 00720 default: 00721 prvSendStall(); 00722 break; 00723 } 00724 } 00725 /*-----------------------------------------------------------*/ 00726 00727 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest ) 00728 { 00729 switch( pxRequest->ucRequest ) 00730 { 00731 /* This minimal implementation does not expect to respond to these. */ 00732 case usbGET_STATUS_REQUEST: 00733 case usbCLEAR_FEATURE_REQUEST: 00734 case usbSET_FEATURE_REQUEST: 00735 00736 default: 00737 prvSendStall(); 00738 break; 00739 } 00740 } 00741 /*-----------------------------------------------------------*/ 00742 00743 static void vDetachUSBInterface( void) 00744 { 00745 /* Setup the PIO for the USB pull up resistor. */ 00746 00747 // MakingThings: PA11, now for Pullup 00748 /* Start without the pullup - this will get set at the end of this 00749 function. */ 00750 #if ( CONTROLLER_VERSION == 90 ) 00751 AT91C_BASE_PIOB->PIO_PER = AT91C_PIO_PB11; 00752 AT91C_BASE_PIOB->PIO_OER = AT91C_PIO_PB11; 00753 AT91C_BASE_PIOB->PIO_SODR = AT91C_PIO_PB11; 00754 #elif ( CONTROLLER_VERSION == 95 || CONTROLLER_VERSION == 100 ) 00755 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA11; 00756 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA11; 00757 /* Disable pull up */ 00758 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA11; 00759 #elif ( CONTROLLER_VERSION == 200 ) 00760 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA30; 00761 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA30; 00762 /* Disable pull up */ 00763 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA30; 00764 #endif 00765 } 00766 /*-----------------------------------------------------------*/ 00767 00768 static void vInitUSBInterface( void ) 00769 { 00770 extern void ( vUSB_ISR_Wrapper )( void ); 00771 00772 /* Create the queue used to communicate between the USB ISR and task. */ 00773 xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) ); 00774 00775 /* Create the queues used to hold Rx and Tx characters. */ 00776 xRxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE, ( unsigned portCHAR ) sizeof( struct BulkBufferStruct ) ); 00777 xTxCDC = xQueueCreate( USB_CDC_QUEUE_SIZE + 1, ( unsigned portCHAR ) sizeof( struct BulkBufferStruct ) ); 00778 00779 if( (!xUSBInterruptQueue) || (!xRxCDC) || (!xTxCDC) ) 00780 { 00781 /* Not enough RAM to create queues!. */ 00782 return; 00783 } 00784 00785 /* Initialise a few state variables. */ 00786 pxControlTx.ulNextCharIndex = ( unsigned portLONG ) 0; 00787 pxControlRx.ulNextCharIndex = ( unsigned portLONG ) 0; 00788 ucUSBConfig = ( unsigned portCHAR ) 0; 00789 eDriverState = eNOTHING; 00790 ucControlState = 0; 00791 uiCurrentBank = AT91C_UDP_RX_DATA_BK0; 00792 00793 00794 /* HARDWARE SETUP */ 00795 00796 /* Set the PLL USB Divider */ 00797 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1; 00798 00799 /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */ 00800 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP; 00801 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP); 00802 00803 /* MAKINGTHINGS: ADDITION */ 00804 /* Setup the PIO for USB input */ 00805 #if ( CONTROLLER_VERSION == 90 ) 00806 AT91C_BASE_PIOB->PIO_PER = AT91C_PIO_PB10; 00807 AT91C_BASE_PIOB->PIO_ODR = AT91C_PIO_PB10; 00808 #elif ( CONTROLLER_VERSION == 95 || CONTROLLER_VERSION == 100 ) 00809 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA10; 00810 AT91C_BASE_PIOA->PIO_ODR = AT91C_PIO_PA10; 00811 #elif ( CONTROLLER_VERSION == 200 ) 00812 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA29; 00813 AT91C_BASE_PIOA->PIO_ODR = AT91C_PIO_PA29; 00814 #endif 00815 00816 00817 /* Start without the pullup - this will get set at the end of this 00818 function. */ 00819 #if ( CONTROLLER_VERSION == 90 ) 00820 AT91C_BASE_PIOB->PIO_PER = AT91C_PIO_PB11; 00821 AT91C_BASE_PIOB->PIO_OER = AT91C_PIO_PB11; 00822 AT91C_BASE_PIOB->PIO_SODR = AT91C_PIO_PB11; 00823 #elif ( CONTROLLER_VERSION == 95 || CONTROLLER_VERSION == 100 ) 00824 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA11; 00825 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA11; 00826 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA11; 00827 #elif ( CONTROLLER_VERSION == 200 ) 00828 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA30; 00829 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA30; 00830 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA30; 00831 #endif 00832 00833 /* When using the USB debugger the peripheral registers do not always get 00834 set to the correct default values. To make sure set the relevant registers 00835 manually here. */ 00836 AT91C_BASE_UDP->UDP_IDR = ( unsigned portLONG ) 0xffffffff; 00837 AT91C_BASE_UDP->UDP_ICR = ( unsigned portLONG ) 0xffffffff; 00838 AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned portLONG ) 0x00; 00839 AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned portLONG ) 0x00; 00840 AT91C_BASE_UDP->UDP_CSR[ 2 ] = ( unsigned portLONG ) 0x00; 00841 AT91C_BASE_UDP->UDP_CSR[ 3 ] = ( unsigned portLONG ) 0x00; 00842 AT91C_BASE_UDP->UDP_GLBSTATE = 0; 00843 AT91C_BASE_UDP->UDP_FADDR = 0; 00844 00845 /* Enable the transceiver. */ 00846 AT91C_UDP_TRANSCEIVER_ENABLE = 0; 00847 00848 /* Enable the USB interrupts - other interrupts get enabled as the 00849 enumeration process progresses. */ 00850 AT91F_AIC_ConfigureIt( AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vUSB_ISR_Wrapper ); 00851 AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP; 00852 00853 00854 /* Wait a short while before making our presence known. */ 00855 vTaskDelay( usbINIT_DELAY ); 00856 00857 /* MAKINGTHINGS: ADDITION */ 00858 #if ( CONTROLLER_VERSION == 90 ) 00859 AT91C_BASE_PIOB->PIO_CODR = AT91C_PIO_PB11; 00860 #elif( CONTROLLER_VERSION == 95 || CONTROLLER_VERSION == 100 ) 00861 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA11; 00862 #elif( CONTROLLER_VERSION == 200 ) 00863 AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA30; 00864 #endif 00865 } 00866 /*-----------------------------------------------------------*/ 00867 00868 static void prvSendControlData( unsigned portCHAR *pucData, unsigned portSHORT usRequestedLength, unsigned portLONG ulLengthToSend, portLONG lSendingDescriptor ) 00869 { 00870 if( ( ( unsigned portLONG ) usRequestedLength < ulLengthToSend ) ) 00871 { 00872 /* Cap the data length to that requested. */ 00873 ulLengthToSend = ( unsigned portSHORT ) usRequestedLength; 00874 } 00875 else if( ( ulLengthToSend < ( unsigned portLONG ) usRequestedLength ) && lSendingDescriptor ) 00876 { 00877 /* We are sending a descriptor. If the descriptor is an exact 00878 multiple of the FIFO length then it will have to be terminated 00879 with a NULL packet. Set the state to indicate this if 00880 necessary. */ 00881 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 ) 00882 { 00883 eDriverState = eSENDING_EVEN_DESCRIPTOR; 00884 } 00885 } 00886 00887 /* Here we assume that the previous message has been sent. THERE IS NO 00888 BUFFER OVERFLOW PROTECTION HERE. 00889 00890 Copy the data to send into the buffer as we cannot send it all at once 00891 (if it is greater than 8 bytes in length). */ 00892 memcpy( pxControlTx.ucBuffer, pucData, ulLengthToSend ); 00893 00894 /* Reinitialise the buffer index so we start sending from the start of 00895 the data. */ 00896 pxControlTx.ulTotalDataLength = ulLengthToSend; 00897 pxControlTx.ulNextCharIndex = ( unsigned portLONG ) 0; 00898 00899 /* Send the first 8 bytes now. The rest will get sent in response to 00900 TXCOMP interrupts. */ 00901 prvSendNextSegment(); 00902 } 00903 /*-----------------------------------------------------------*/ 00904 00905 static void prvSendNextSegment( void ) 00906 { 00907 volatile unsigned portLONG ulNextLength, ulStatus, ulLengthLeftToSend; 00908 00909 /* Is there any data to send? */ 00910 if( pxControlTx.ulTotalDataLength > pxControlTx.ulNextCharIndex ) 00911 { 00912 ulLengthLeftToSend = pxControlTx.ulTotalDataLength - pxControlTx.ulNextCharIndex; 00913 00914 /* We can only send 8 bytes to the fifo at a time. */ 00915 if( ulLengthLeftToSend > usbFIFO_LENGTH ) 00916 { 00917 ulNextLength = usbFIFO_LENGTH; 00918 } 00919 else 00920 { 00921 ulNextLength = ulLengthLeftToSend; 00922 } 00923 00924 /* Wait until we can place data in the fifo. THERE IS NO TIMEOUT 00925 HERE! */ 00926 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY ) 00927 { 00928 vTaskDelay( usbSHORTEST_DELAY ); 00929 } 00930 00931 /* Write the data to the FIFO. */ 00932 while( ulNextLength > ( unsigned portLONG ) 0 ) 00933 { 00934 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxControlTx.ucBuffer[ pxControlTx.ulNextCharIndex ]; 00935 00936 ulNextLength--; 00937 pxControlTx.ulNextCharIndex++; 00938 } 00939 00940 /* Start the transmission. */ 00941 portENTER_CRITICAL(); 00942 { 00943 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ]; 00944 usbCSR_SET_BIT( &ulStatus, ( ( unsigned portLONG ) 0x10 ) ); 00945 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus; 00946 } 00947 portEXIT_CRITICAL(); 00948 } 00949 else 00950 { 00951 /* There is no data to send. If we were sending a descriptor and the 00952 descriptor was an exact multiple of the max packet 00953 then we need 00954 to send a null to terminate the transmission. */ 00955 if( eDriverState == eSENDING_EVEN_DESCRIPTOR ) 00956 { 00957 prvSendZLP(usbEND_POINT_0); 00958 eDriverState = eNOTHING; 00959 } 00960 } 00961 } 00962 00963 #endif // MAKE_CTRL_USB 00964 00965
The Make Controller Kit is an open source project maintained by MakingThings.
MakingThings code is released under the Apache 2.0 license.
Bug tracker, development wiki and status can be found at http://dev.makingthings.com.
This document was last updated on 18 May 2009.