- 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.