]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_A5_SAMA5D3x_Xplained_IAR/AtmelFiles/usb/device/core/USBD.c
SAMA5D3 demo: Add CDC driver code and use CDC to create a simple command console.
[freertos] / FreeRTOS / Demo / CORTEX_A5_SAMA5D3x_Xplained_IAR / AtmelFiles / usb / device / core / USBD.c
1 /* ----------------------------------------------------------------------------\r
2  *         ATMEL Microcontroller Software Support\r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2008, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * Atmel's name may not be used to endorse or promote products derived from\r
15  * this software without specific prior written permission.\r
16  *\r
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  * ----------------------------------------------------------------------------\r
28  */\r
29 \r
30 /** \file\r
31  *\r
32  *  \section Purpose\r
33  *\r
34  *  Implementation of USB device functions on a UDP controller.\r
35  *\r
36  *  See \ref usbd_api "USBD API Methods".\r
37  */\r
38 \r
39 /** \addtogroup usbd_interface\r
40  *@{\r
41  */\r
42 \r
43 /*---------------------------------------------------------------------------\r
44  *      Headers\r
45  *---------------------------------------------------------------------------*/\r
46 \r
47 #include "USBD.h"\r
48 #include "USBD_HAL.h"\r
49 \r
50 #include <USBLib_Trace.h>\r
51 \r
52 /*---------------------------------------------------------------------------\r
53  *      Definitions\r
54  *---------------------------------------------------------------------------*/\r
55 \r
56 /*---------------------------------------------------------------------------\r
57  *      Internal variables\r
58  *---------------------------------------------------------------------------*/\r
59 \r
60 /** Device current state. */\r
61 static uint8_t deviceState;\r
62 /** Indicates the previous device state */\r
63 static uint8_t previousDeviceState;\r
64 \r
65 /*---------------------------------------------------------------------------\r
66  *      Internal Functions\r
67  *---------------------------------------------------------------------------*/\r
68 \r
69 /*---------------------------------------------------------------------------\r
70  *      Exported functions\r
71  *---------------------------------------------------------------------------*/\r
72 \r
73 /*---------------------------------------------------------------------------\r
74  *      USBD: Event handlers\r
75  *---------------------------------------------------------------------------*/\r
76 \r
77 /**\r
78  *  Handle the USB suspend event, should be invoked whenever\r
79  *  HW reports a suspend signal.\r
80  */\r
81 void USBD_SuspendHandler(void)\r
82 {\r
83     /* Don't do anything if the device is already suspended */\r
84     if (deviceState != USBD_STATE_SUSPENDED) {\r
85 \r
86         /* Switch to the Suspended state */\r
87         previousDeviceState = deviceState;\r
88         deviceState = USBD_STATE_SUSPENDED;\r
89 \r
90         /* Suspend HW interface */\r
91         USBD_HAL_Suspend();\r
92 \r
93         /* Invoke the User Suspended callback (Suspend System?) */\r
94         if (NULL != USBDCallbacks_Suspended)\r
95             USBDCallbacks_Suspended();\r
96     }\r
97 }\r
98 \r
99 /**\r
100  *  Handle the USB resume event, should be invoked whenever\r
101  *  HW reports a resume signal.\r
102  */\r
103 void USBD_ResumeHandler(void)\r
104 {\r
105     /* Don't do anything if the device was not suspended */\r
106     if (deviceState == USBD_STATE_SUSPENDED) {\r
107         /* Active the device */\r
108         USBD_HAL_Activate();\r
109         deviceState = previousDeviceState;\r
110         if (deviceState >= USBD_STATE_DEFAULT) {\r
111             /* Invoke the Resume callback */\r
112             if (NULL != USBDCallbacks_Resumed)\r
113                 USBDCallbacks_Resumed();\r
114         }\r
115     }\r
116 }\r
117 \r
118 /**\r
119  *  Handle the USB reset event, should be invoked whenever\r
120  *  HW found USB reset signal on bus, which usually is called\r
121  *  "end of bus reset" status.\r
122  */\r
123 void USBD_ResetHandler()\r
124 {\r
125     /* The device enters the Default state */\r
126     deviceState = USBD_STATE_DEFAULT;\r
127     /* Active the USB HW */\r
128     USBD_HAL_Activate();\r
129     /* Only EP0 enabled */\r
130     USBD_HAL_ResetEPs(0xFFFFFFFF, USBD_STATUS_RESET, 0);\r
131     USBD_ConfigureEndpoint(0);\r
132     /* Invoke the Reset callback */\r
133     if (NULL != USBDCallbacks_Reset)\r
134         USBDCallbacks_Reset();\r
135 }\r
136 \r
137 /**\r
138  *  Handle the USB setup package received, should be invoked\r
139  *  when an endpoint got a setup package as request.\r
140  *  \param bEndpoint Endpoint number.\r
141  *  \param pRequest  Pointer to content of request.\r
142  */\r
143 void USBD_RequestHandler(uint8_t bEndpoint,\r
144                          const USBGenericRequest* pRequest)\r
145 {\r
146     if (bEndpoint != 0) {\r
147         TRACE_WARNING("EP%d request not supported, default EP only",\r
148                       bEndpoint);\r
149     }\r
150     else if (NULL != USBDCallbacks_RequestReceived) {\r
151         USBDCallbacks_RequestReceived(pRequest);\r
152     }\r
153 }\r
154 \r
155 /*---------------------------------------------------------------------------\r
156  *      USBD: Library interface\r
157  *---------------------------------------------------------------------------*/\r
158 \r
159 /**\r
160  * Configures an endpoint according to its Endpoint Descriptor.\r
161  * \param pDescriptor Pointer to an Endpoint descriptor.\r
162  */\r
163 void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor)\r
164 {\r
165     USBD_HAL_ConfigureEP(pDescriptor);\r
166 }\r
167 \r
168 /**\r
169  * Sends data through a USB endpoint. Sets up the transfer descriptor,\r
170  * writes one or two data payloads (depending on the number of FIFO bank\r
171  * for the endpoint) and then starts the actual transfer. The operation is\r
172  * complete when all the data has been sent.\r
173  *\r
174  * *If the size of the buffer is greater than the size of the endpoint\r
175  *  (or twice the size if the endpoint has two FIFO banks), then the buffer\r
176  *  must be kept allocated until the transfer is finished*. This means that\r
177  *  it is not possible to declare it on the stack (i.e. as a local variable\r
178  *  of a function which returns after starting a transfer).\r
179  *\r
180  * \param bEndpoint Endpoint number.\r
181  * \param pData Pointer to a buffer with the data to send.\r
182  * \param dLength Size of the data buffer.\r
183  * \param fCallback Optional callback function to invoke when the transfer is\r
184  *        complete.\r
185  * \param pArgument Optional argument to the callback function.\r
186  * \return USBD_STATUS_SUCCESS if the transfer has been started;\r
187  *         otherwise, the corresponding error status code.\r
188  */\r
189 uint8_t USBD_Write( uint8_t          bEndpoint,\r
190                     const void       *pData,\r
191                     uint32_t         dLength,\r
192                     TransferCallback fCallback,\r
193                     void             *pArgument )\r
194 {\r
195     USBD_HAL_SetTransferCallback(bEndpoint, fCallback, pArgument);\r
196     return USBD_HAL_Write(bEndpoint, pData, dLength);\r
197 }\r
198 #if 0\r
199 /**\r
200  * Sends data frames through a USB endpoint. Sets up the transfer descriptor\r
201  * list, writes one or two data payloads (depending on the number of FIFO bank\r
202  * for the endpoint) and then starts the actual transfer. The operation is\r
203  * complete when all the data has been sent.\r
204  *\r
205  * *If the size of the frame is greater than the size of the endpoint\r
206  *  (or twice the size if the endpoint has two FIFO banks), then the buffer\r
207  *  must be kept allocated until the frame is finished*. This means that\r
208  *  it is not possible to declare it on the stack (i.e. as a local variable\r
209  *  of a function which returns after starting a transfer).\r
210  *\r
211  * \param bEndpoint Endpoint number.\r
212  * \param pMbl Pointer to a frame (USBDTransferBuffer) list that describes\r
213  *             the buffer list to send.\r
214  * \param wListSize Size of the frame list.\r
215  * \param bCircList Circle the list.\r
216  * \param wStartNdx For circled list only, the first buffer index to transfer.\r
217  * \param fCallback Optional callback function to invoke when the transfer is\r
218  *        complete.\r
219  * \param pArgument Optional argument to the callback function.\r
220  * \return USBD_STATUS_SUCCESS if the transfer has been started;\r
221  *         otherwise, the corresponding error status code.\r
222  * \see USBDTransferBuffer, MblTransferCallback, USBD_MblReuse\r
223  */\r
224 uint8_t USBD_MblWrite( uint8_t       bEndpoint,\r
225                     void                *pMbl,\r
226                     uint16_t      wListSize,\r
227                     uint8_t       bCircList,\r
228                     uint16_t      wStartNdx,\r
229                     MblTransferCallback fCallback,\r
230                     void                *pArgument )\r
231 {\r
232     Endpoint    *pEndpoint = &(endpoints[bEndpoint]);\r
233     MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);\r
234     uint16_t i;\r
235 \r
236     /* EP0 is not suitable for Mbl */\r
237 \r
238     if (bEndpoint == 0) {\r
239 \r
240         return USBD_STATUS_INVALID_PARAMETER;\r
241     }\r
242 \r
243     /* Check that the endpoint is in Idle state */\r
244 \r
245     if (pEndpoint->state != UDP_ENDPOINT_IDLE) {\r
246 \r
247         return USBD_STATUS_LOCKED;\r
248     }\r
249     pEndpoint->state = UDP_ENDPOINT_SENDINGM;\r
250 \r
251     TRACE_DEBUG_WP("WriteM%d(0x%x,%d) ", bEndpoint, pMbl, wListSize);\r
252 \r
253     /* Start from first if not circled list */\r
254 \r
255     if (!bCircList) wStartNdx = 0;\r
256 \r
257     /* Setup the transfer descriptor */\r
258 \r
259     pTransfer->pMbl        = (USBDTransferBuffer*)pMbl;\r
260     pTransfer->listSize    = wListSize;\r
261     pTransfer->fCallback   = fCallback;\r
262     pTransfer->pArgument   = pArgument;\r
263     pTransfer->currBuffer  = wStartNdx;\r
264     pTransfer->freedBuffer = 0;\r
265     pTransfer->pLastLoaded = &(((USBDTransferBuffer*)pMbl)[wStartNdx]);\r
266     pTransfer->circList    = bCircList;\r
267     pTransfer->allUsed     = 0;\r
268 \r
269     /* Clear all buffer */\r
270 \r
271     for (i = 0; i < wListSize; i ++) {\r
272 \r
273         pTransfer->pMbl[i].transferred = 0;\r
274         pTransfer->pMbl[i].buffered   = 0;\r
275         pTransfer->pMbl[i].remaining   = pTransfer->pMbl[i].size;\r
276     }\r
277 \r
278     /* Send the first packet */\r
279 \r
280     while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY);\r
281     UDP_MblWriteFifo(bEndpoint);\r
282     SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);\r
283 \r
284     /* If double buffering is enabled and there is data remaining, */\r
285 \r
286     /* prepare another packet */\r
287 \r
288     if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1)\r
289         && (pTransfer->pMbl[pTransfer->currBuffer].remaining > 0)) {\r
290 \r
291         UDP_MblWriteFifo(bEndpoint);\r
292     }\r
293 \r
294     /* Enable interrupt on endpoint */\r
295 \r
296     UDP->UDP_IER = 1 << bEndpoint;\r
297 \r
298     return USBD_STATUS_SUCCESS;\r
299 }\r
300 #endif\r
301 /**\r
302  * Reads incoming data on an USB endpoint This methods sets the transfer\r
303  * descriptor and activate the endpoint interrupt. The actual transfer is\r
304  * then carried out by the endpoint interrupt handler. The Read operation\r
305  * finishes either when the buffer is full, or a short packet (inferior to\r
306  * endpoint maximum  size) is received.\r
307  *\r
308  * *The buffer must be kept allocated until the transfer is finished*.\r
309  * \param bEndpoint Endpoint number.\r
310  * \param pData Pointer to a data buffer.\r
311  * \param dLength Size of the data buffer in bytes.\r
312  * \param fCallback Optional end-of-transfer callback function.\r
313  * \param pArgument Optional argument to the callback function.\r
314  * \return USBD_STATUS_SUCCESS if the read operation has been started;\r
315  *         otherwise, the corresponding error code.\r
316  */\r
317 uint8_t USBD_Read(uint8_t          bEndpoint,\r
318                   void             *pData,\r
319                   uint32_t         dLength,\r
320                   TransferCallback fCallback,\r
321                   void             *pArgument)\r
322 {\r
323     USBD_HAL_SetTransferCallback(bEndpoint, fCallback, pArgument);\r
324     return USBD_HAL_Read(bEndpoint, pData, dLength);\r
325 }\r
326 #if 0\r
327 /**\r
328  * Reuse first used/released buffer with new buffer address and size to be used\r
329  * in transfer again. Only valid when frame list is ringed. Can be used for\r
330  * both read & write.\r
331  * \param bEndpoint  Endpoint number.\r
332  * \param pNewBuffer Pointer to new buffer with data to send (0 to keep last).\r
333  * \param wNewSize   Size of the data buffer\r
334  */\r
335 uint8_t USBD_MblReuse( uint8_t  bEndpoint,\r
336                     uint8_t  *pNewBuffer,\r
337                     uint16_t wNewSize )\r
338 {\r
339     Endpoint *pEndpoint = &(endpoints[bEndpoint]);\r
340     MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);\r
341     USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->freedBuffer]);\r
342 \r
343     TRACE_DEBUG_WP("MblReuse(%d), st%x, circ%d\n\r",\r
344         bEndpoint, pEndpoint->state, pTransfer->circList);\r
345 \r
346     /* Only for Multi-buffer-circle list */\r
347 \r
348     if (bEndpoint != 0\r
349         && (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM\r
350             || pEndpoint->state == UDP_ENDPOINT_SENDINGM)\r
351         && pTransfer->circList) {\r
352     }\r
353     else {\r
354 \r
355         return USBD_STATUS_WRONG_STATE;\r
356     }\r
357 \r
358     /* Check if there is freed buffer */\r
359 \r
360     if (pTransfer->freedBuffer == pTransfer->currBuffer\r
361         && !pTransfer->allUsed) {\r
362 \r
363         return USBD_STATUS_LOCKED;\r
364    }\r
365 \r
366     /* Update transfer information */\r
367 \r
368     if ((++ pTransfer->freedBuffer) == pTransfer->listSize)\r
369         pTransfer->freedBuffer = 0;\r
370     if (pNewBuffer) {\r
371         pBi->pBuffer = pNewBuffer;\r
372         pBi->size    = wNewSize;\r
373     }\r
374     pBi->buffered    = 0;\r
375     pBi->transferred = 0;\r
376     pBi->remaining   = pBi->size;\r
377 \r
378     /* At least one buffer is not processed */\r
379 \r
380     pTransfer->allUsed = 0;\r
381     return USBD_STATUS_SUCCESS;\r
382 }\r
383 #endif\r
384 /**\r
385  * Sets the HALT feature on the given endpoint (if not already in this state).\r
386  * \param bEndpoint Endpoint number.\r
387  */\r
388 void USBD_Halt(uint8_t bEndpoint)\r
389 {\r
390     USBD_HAL_Halt(bEndpoint, 1);\r
391 }\r
392 \r
393 /**\r
394  * Clears the Halt feature on the given endpoint.\r
395  * \param bEndpoint Index of endpoint\r
396  */\r
397 void USBD_Unhalt(uint8_t bEndpoint)\r
398 {\r
399     USBD_HAL_Halt(bEndpoint, 0);\r
400 }\r
401 \r
402 /**\r
403  * Returns the current Halt status of an endpoint.\r
404  * \param bEndpoint Index of endpoint\r
405  * \return 1 if the endpoint is currently halted; otherwise 0\r
406  */\r
407 uint8_t USBD_IsHalted(uint8_t bEndpoint)\r
408 {\r
409     return USBD_HAL_Halt(bEndpoint, 0xFF);\r
410 }\r
411 \r
412 /**\r
413  * Indicates if the device is running in high or full-speed. Always returns 0\r
414  * since UDP does not support high-speed mode.\r
415  */\r
416 uint8_t USBD_IsHighSpeed(void)\r
417 {\r
418     return USBD_HAL_IsHighSpeed();\r
419 }\r
420 \r
421 /**\r
422  * Causes the given endpoint to acknowledge the next packet it receives\r
423  * with a STALL handshake.\r
424  * \param bEndpoint Endpoint number.\r
425  * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED.\r
426  */\r
427 uint8_t USBD_Stall(uint8_t bEndpoint)\r
428 \r
429 {\r
430     return USBD_HAL_Stall(bEndpoint);\r
431 }\r
432 \r
433 /**\r
434  * Sets the device address to the given value.\r
435  * \param address New device address.\r
436  */\r
437 void USBD_SetAddress(uint8_t address)\r
438 {\r
439     TRACE_INFO_WP("SetAddr(%d) ", address);\r
440 \r
441     USBD_HAL_SetAddress(address);\r
442     if (address == 0) deviceState = USBD_STATE_DEFAULT;\r
443     else              deviceState = USBD_STATE_ADDRESS;\r
444 }\r
445 \r
446 /**\r
447  * Sets the current device configuration.\r
448  * \param cfgnum - Configuration number to set.\r
449  */\r
450 void USBD_SetConfiguration(uint8_t cfgnum)\r
451 {\r
452     TRACE_INFO_WP("SetCfg(%d) ", cfgnum);\r
453 \r
454     USBD_HAL_SetConfiguration(cfgnum);\r
455 \r
456     if (cfgnum != 0) {\r
457         deviceState = USBD_STATE_CONFIGURED;\r
458     }\r
459     else {\r
460         deviceState = USBD_STATE_ADDRESS;\r
461         /* Reset all endpoints but Control 0 */\r
462         USBD_HAL_ResetEPs(0xFFFFFFFE, USBD_STATUS_RESET, 0);\r
463     }\r
464 }\r
465 \r
466 /*---------------------------------------------------------------------------\r
467  *      USBD: Library API\r
468  *---------------------------------------------------------------------------*/\r
469 \r
470 /**\r
471  * Starts a remote wake-up procedure.\r
472  */\r
473 void USBD_RemoteWakeUp(void)\r
474 {\r
475     /* Device is NOT suspended */\r
476     if (deviceState != USBD_STATE_SUSPENDED) {\r
477 \r
478         TRACE_INFO("USBD_RemoteWakeUp: Device is not suspended\n\r");\r
479         return;\r
480     }\r
481     USBD_HAL_Activate();\r
482     USBD_HAL_RemoteWakeUp();\r
483 }\r
484 \r
485 /**\r
486  * Connects the pull-up on the D+ line of the USB.\r
487  */\r
488 void USBD_Connect(void)\r
489 {\r
490     USBD_HAL_Connect();\r
491 }\r
492 \r
493 /**\r
494  * Disconnects the pull-up from the D+ line of the USB.\r
495  */\r
496 void USBD_Disconnect(void)\r
497 {\r
498     USBD_HAL_Disconnect();\r
499 \r
500     /* Device returns to the Powered state */\r
501 \r
502     if (deviceState > USBD_STATE_POWERED) {\r
503 \r
504         deviceState = USBD_STATE_POWERED;\r
505     }\r
506 \r
507     if (previousDeviceState > USBD_STATE_POWERED) {\r
508 \r
509         previousDeviceState = USBD_STATE_POWERED;\r
510     }\r
511 }\r
512 \r
513 /**\r
514  * Initializes the USB driver.\r
515  */\r
516 void USBD_Init(void)\r
517 {\r
518     TRACE_INFO_WP("USBD_Init\n\r");\r
519 \r
520     /* HW Layer Initialize */\r
521     USBD_HAL_Init();\r
522 \r
523     /* Device is in the Attached state */\r
524     deviceState = USBD_STATE_SUSPENDED;\r
525     previousDeviceState = USBD_STATE_POWERED;\r
526 \r
527     /* Upper Layer Initialize */\r
528     if (NULL != USBDCallbacks_Initialized)\r
529         USBDCallbacks_Initialized();\r
530 }\r
531 \r
532 /**\r
533  * Returns the current state of the USB device.\r
534  * \return Device current state.\r
535  */\r
536 uint8_t USBD_GetState(void)\r
537 {\r
538     return deviceState;\r
539 }\r
540 \r
541 /**\r
542  * Certification test for High Speed device.\r
543  * \param bIndex Test to be done\r
544  */\r
545 void USBD_Test(uint8_t bIndex)\r
546 {\r
547     USBD_HAL_Test(bIndex);\r
548 }\r
549 \r
550 /**@}*/\r