MakingThings
  • Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

USB-CDC.c

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.