1 /**************************************************************************//**
2  * @file     usbd.c
3  * @version  V1.00
4  * @brief    M480 USBD driver source file
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  * @copyright (C) 2016-2020 Nuvoton Technology Corp. All rights reserved.
8 *****************************************************************************/
9 
10 #include <string.h>
11 #include "NuMicro.h"
12 
13 #ifdef __cplusplus
14 extern "C"
15 {
16 #endif
17 
18 /** @addtogroup Standard_Driver Standard Driver
19   @{
20 */
21 
22 /** @addtogroup USBD_Driver USBD Driver
23   @{
24 */
25 
26 
27 /** @addtogroup USBD_EXPORTED_FUNCTIONS USBD Exported Functions
28   @{
29 */
30 
31 /* Global variables for Control Pipe */
32 uint8_t g_usbd_SetupPacket[8] = {0ul};        /*!< Setup packet buffer */
33 volatile uint8_t g_usbd_RemoteWakeupEn = 0ul; /*!< Remote wake up function enable flag */
34 
35 /**
36  * @cond HIDDEN_SYMBOLS
37  */
38 static uint8_t *g_usbd_CtrlInPointer = 0;
39 static uint8_t *g_usbd_CtrlOutPointer = 0;
40 static volatile uint32_t g_usbd_CtrlInSize = 0ul;
41 static volatile uint32_t g_usbd_CtrlOutSize = 0ul;
42 static volatile uint32_t g_usbd_CtrlOutSizeLimit = 0ul;
43 static volatile uint32_t g_usbd_UsbAddr = 0ul;
44 static volatile uint32_t g_usbd_UsbConfig = 0ul;
45 static volatile uint32_t g_usbd_CtrlMaxPktSize = 8ul;
46 static volatile uint32_t g_usbd_UsbAltInterface = 0ul;
47 static volatile uint32_t g_usbd_CtrlOutToggle = 0;
48 static volatile uint8_t g_usbd_CtrlInZeroFlag = 0ul;
49 /**
50  * @endcond
51  */
52 
53 const S_USBD_INFO_T *g_usbd_sInfo;                  /*!< A pointer for USB information structure */
54 
55 VENDOR_REQ g_usbd_pfnVendorRequest       = NULL;    /*!< USB Vendor Request Functional Pointer */
56 CLASS_REQ g_usbd_pfnClassRequest         = NULL;    /*!< USB Class Request Functional Pointer */
57 SET_INTERFACE_REQ g_usbd_pfnSetInterface = NULL;    /*!< USB Set Interface Functional Pointer */
58 SET_CONFIG_CB g_usbd_pfnSetConfigCallback = NULL;   /*!< USB Set configuration callback function pointer */
59 uint32_t g_u32EpStallLock                = 0ul;       /*!< Bit map flag to lock specified EP when SET_FEATURE */
60 
61 /**
62   * @brief      This function makes USBD module to be ready to use
63   *
64   * @param[in]  param           The structure of USBD information.
65   * @param[in]  pfnClassReq     USB Class request callback function.
66   * @param[in]  pfnSetInterface USB Set Interface request callback function.
67   *
68   * @return     None
69   *
70   * @details    This function will enable USB controller, USB PHY transceiver and pull-up resistor of USB_D+ pin. USB PHY will drive SE0 to bus.
71   */
USBD_Open(const S_USBD_INFO_T * param,CLASS_REQ pfnClassReq,SET_INTERFACE_REQ pfnSetInterface)72 void USBD_Open(const S_USBD_INFO_T *param, CLASS_REQ pfnClassReq, SET_INTERFACE_REQ pfnSetInterface)
73 {
74     g_usbd_sInfo = param;
75     g_usbd_pfnClassRequest = pfnClassReq;
76     g_usbd_pfnSetInterface = pfnSetInterface;
77 
78     /* get EP0 maximum packet size */
79     g_usbd_CtrlMaxPktSize = g_usbd_sInfo->gu8DevDesc[7];
80 
81     /* Initial USB engine */
82     USBD->ATTR = 0x6D0ul;
83     /* Force SE0 */
84     USBD_SET_SE0();
85 }
86 
87 /**
88   * @brief    This function makes USB host to recognize the device
89   *
90   * @param    None
91   *
92   * @return   None
93   *
94   * @details  Enable WAKEUP, FLDET, USB and BUS interrupts. Disable software-disconnect function after 100ms delay with SysTick timer.
95   */
USBD_Start(void)96 void USBD_Start(void)
97 {
98     /* Disable software-disconnect function */
99     USBD_CLR_SE0();
100     USBD->ATTR = 0x7D0ul;
101 
102     /* Clear USB-related interrupts before enable interrupt */
103     USBD_CLR_INT_FLAG(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP);
104 
105     /* Enable USB-related interrupts. */
106     USBD_ENABLE_INT(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP);
107 }
108 
109 /**
110   * @brief      Get the received SETUP packet
111   *
112   * @param[in]  buf A buffer pointer used to store 8-byte SETUP packet.
113   *
114   * @return     None
115   *
116   * @details    Store SETUP packet to a user-specified buffer.
117   *
118   */
USBD_GetSetupPacket(uint8_t * buf)119 void USBD_GetSetupPacket(uint8_t *buf)
120 {
121     USBD_MemCopy(buf, g_usbd_SetupPacket, 8ul);
122 }
123 
124 /**
125   * @brief    Process SETUP packet
126   *
127   * @param    None
128   *
129   * @return   None
130   *
131   * @details  Parse SETUP packet and perform the corresponding action.
132   *
133   */
USBD_ProcessSetupPacket(void)134 void USBD_ProcessSetupPacket(void)
135 {
136     g_usbd_CtrlOutToggle = 0;
137     /* Get SETUP packet from USB buffer */
138     USBD_MemCopy(g_usbd_SetupPacket, (uint8_t *)USBD_BUF_BASE, 8ul);
139 
140     /* Check the request type */
141     switch(g_usbd_SetupPacket[0] & 0x60ul)
142     {
143     case REQ_STANDARD:
144     {
145         USBD_StandardRequest();
146         break;
147     }
148     case REQ_CLASS:
149     {
150         if(g_usbd_pfnClassRequest != NULL)
151         {
152             g_usbd_pfnClassRequest();
153         }
154         break;
155     }
156     case REQ_VENDOR:
157     {
158         if(g_usbd_pfnVendorRequest != NULL)
159         {
160             g_usbd_pfnVendorRequest();
161         }
162         break;
163     }
164     default:
165     {
166         /* Setup error, stall the device */
167         USBD_SET_EP_STALL(EP0);
168         USBD_SET_EP_STALL(EP1);
169         break;
170     }
171     }
172 }
173 
174 /**
175   * @brief    Process GetDescriptor request
176   *
177   * @param    None
178   *
179   * @return   None
180   *
181   * @details  Parse GetDescriptor request and perform the corresponding action.
182   *
183   */
USBD_GetDescriptor(void)184 void USBD_GetDescriptor(void)
185 {
186     uint32_t u32Len;
187 
188     g_usbd_CtrlInZeroFlag = (uint8_t)0ul;
189     u32Len = 0ul;
190     u32Len = g_usbd_SetupPacket[7];
191     u32Len <<= 8ul;
192     u32Len += g_usbd_SetupPacket[6];
193 
194     switch(g_usbd_SetupPacket[3])
195     {
196     /* Get Device Descriptor */
197     case DESC_DEVICE:
198     {
199         u32Len = USBD_Minimum(u32Len, (uint32_t)LEN_DEVICE);
200         USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8DevDesc, u32Len);
201 
202         break;
203     }
204     /* Get Configuration Descriptor */
205     case DESC_CONFIG:
206     {
207         uint32_t u32TotalLen;
208 
209         u32TotalLen = g_usbd_sInfo->gu8ConfigDesc[3];
210         u32TotalLen = g_usbd_sInfo->gu8ConfigDesc[2] + (u32TotalLen << 8);
211 
212         if (u32Len > u32TotalLen)
213         {
214             u32Len = u32TotalLen;
215             if ((u32Len % g_usbd_CtrlMaxPktSize) == 0ul)
216             {
217                 g_usbd_CtrlInZeroFlag = (uint8_t)1ul;
218             }
219         }
220         USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8ConfigDesc, u32Len);
221 
222         break;
223     }
224 
225     /* Get BOS Descriptor */
226     case DESC_BOS:
227     {
228         if (g_usbd_sInfo->gu8BosDesc == 0)
229         {
230             USBD_SET_EP_STALL(EP0);
231             USBD_SET_EP_STALL(EP1);
232         }
233         else
234         {
235             u32Len = USBD_Minimum(u32Len, LEN_BOS+LEN_BOSCAP);
236             USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8BosDesc, u32Len);
237         }
238         break;
239     }
240     /* Get HID Descriptor */
241     case DESC_HID:
242     {
243         /* CV3.0 HID Class Descriptor Test,
244            Need to indicate index of the HID Descriptor within gu8ConfigDescriptor, specifically HID Composite device. */
245         uint32_t u32ConfigDescOffset;   /* u32ConfigDescOffset is configuration descriptor offset (HID descriptor start index) */
246         u32Len = USBD_Minimum(u32Len, LEN_HID);
247         u32ConfigDescOffset = g_usbd_sInfo->gu32ConfigHidDescIdx[g_usbd_SetupPacket[4]];
248         USBD_PrepareCtrlIn((uint8_t *)&g_usbd_sInfo->gu8ConfigDesc[u32ConfigDescOffset], u32Len);
249 
250         break;
251     }
252     /* Get Report Descriptor */
253     case DESC_HID_RPT:
254     {
255         if (u32Len > g_usbd_sInfo->gu32HidReportSize[g_usbd_SetupPacket[4]])
256         {
257             u32Len = g_usbd_sInfo->gu32HidReportSize[g_usbd_SetupPacket[4]];
258             if ((u32Len % g_usbd_CtrlMaxPktSize) == 0ul)
259             {
260                 g_usbd_CtrlInZeroFlag = (uint8_t)1ul;
261             }
262         }
263         USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8HidReportDesc[g_usbd_SetupPacket[4]], u32Len);
264         break;
265     }
266     /* Get String Descriptor */
267     case DESC_STRING:
268     {
269         /* Get String Descriptor */
270         if(g_usbd_SetupPacket[2] < 4ul)
271         {
272             if (u32Len > g_usbd_sInfo->gu8StringDesc[g_usbd_SetupPacket[2]][0])
273             {
274                 u32Len = g_usbd_sInfo->gu8StringDesc[g_usbd_SetupPacket[2]][0];
275                 if ((u32Len % g_usbd_CtrlMaxPktSize) == 0ul)
276                 {
277                     g_usbd_CtrlInZeroFlag = (uint8_t)1ul;
278                 }
279             }
280             USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8StringDesc[g_usbd_SetupPacket[2]], u32Len);
281             break;
282         }
283         else
284         {
285             /* Not support. Reply STALL. */
286             USBD_SET_EP_STALL(EP0);
287             USBD_SET_EP_STALL(EP1);
288             break;
289         }
290     }
291     default:
292         /* Not support. Reply STALL.*/
293         USBD_SET_EP_STALL(EP0);
294         USBD_SET_EP_STALL(EP1);
295         break;
296     }
297 }
298 
299 /**
300   * @brief    Process standard request
301   *
302   * @param    None
303   *
304   * @return   None
305   *
306   * @details  Parse standard request and perform the corresponding action.
307   *
308   */
USBD_StandardRequest(void)309 void USBD_StandardRequest(void)
310 {
311     uint32_t addr;
312     /* clear global variables for new request */
313     g_usbd_CtrlInPointer = 0;
314     g_usbd_CtrlInSize = 0ul;
315 
316     if((g_usbd_SetupPacket[0] & 0x80ul) == 0x80ul)    /* request data transfer direction */
317     {
318         /* Device to host */
319         switch(g_usbd_SetupPacket[1])
320         {
321         case GET_CONFIGURATION:
322         {
323             /* Return current configuration setting */
324             /* Data stage */
325             addr = USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0);
326             M8(addr) = (uint8_t)g_usbd_UsbConfig;
327             USBD_SET_DATA1(EP0);
328             USBD_SET_PAYLOAD_LEN(EP0, 1ul);
329             /* Status stage */
330             USBD_PrepareCtrlOut(0, 0ul);
331             break;
332         }
333         case GET_DESCRIPTOR:
334         {
335             USBD_GetDescriptor();
336             USBD_PrepareCtrlOut(0, 0ul); /* For status stage */
337             break;
338         }
339         case GET_INTERFACE:
340         {
341             /* Return current interface setting */
342             /* Data stage */
343             addr = USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0);
344             M8(addr) = (uint8_t)g_usbd_UsbAltInterface;
345             USBD_SET_DATA1(EP0);
346             USBD_SET_PAYLOAD_LEN(EP0, 1ul);
347             /* Status stage */
348             USBD_PrepareCtrlOut(0, 0ul);
349             break;
350         }
351         case GET_STATUS:
352         {
353             /* Device */
354             if(g_usbd_SetupPacket[0] == 0x80ul)
355             {
356                 uint8_t u8Tmp;
357 
358                 u8Tmp = (uint8_t)0ul;
359                 if ((g_usbd_sInfo->gu8ConfigDesc[7] & 0x40ul) == 0x40ul)
360                 {
361                     u8Tmp |= (uint8_t)1ul; /* Self-Powered/Bus-Powered.*/
362                 }
363                 if ((g_usbd_sInfo->gu8ConfigDesc[7] & 0x20ul) == 0x20ul)
364                 {
365                     u8Tmp |= (uint8_t)(g_usbd_RemoteWakeupEn << 1ul); /* Remote wake up */
366                 }
367 
368                 addr = USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0);
369                 M8(addr) = u8Tmp;
370 
371             }
372             /* Interface */
373             else if(g_usbd_SetupPacket[0] == 0x81ul)
374             {
375                 addr = USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0);
376                 M8(addr) = (uint8_t)0ul;
377             }
378             /* Endpoint */
379             else if(g_usbd_SetupPacket[0] == 0x82ul)
380             {
381                 uint8_t ep = (uint8_t)(g_usbd_SetupPacket[4] & 0xFul);
382                 addr = USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0);
383                 M8(addr) = (uint8_t)(USBD_GetStall(ep) ? 1ul : 0ul);
384             }
385 
386             addr = USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0) + 1ul;
387             M8(addr) = (uint8_t)0ul;
388             /* Data stage */
389             USBD_SET_DATA1(EP0);
390             USBD_SET_PAYLOAD_LEN(EP0, 2ul);
391             /* Status stage */
392             USBD_PrepareCtrlOut(0, 0ul);
393             break;
394         }
395         default:
396         {
397             /* Setup error, stall the device */
398             USBD_SET_EP_STALL(EP0);
399             USBD_SET_EP_STALL(EP1);
400             break;
401         }
402         }
403     }
404     else
405     {
406         /* Host to device */
407         switch(g_usbd_SetupPacket[1])
408         {
409         case CLEAR_FEATURE:
410         {
411             if(g_usbd_SetupPacket[2] == FEATURE_ENDPOINT_HALT)
412             {
413                 uint32_t epNum, i;
414 
415                 /* EP number stall is not allow to be clear in MSC class "Error Recovery Test".
416                    a flag: g_u32EpStallLock is added to support it */
417                 epNum = (uint8_t)(g_usbd_SetupPacket[4] & 0xFul);
418                 for(i = 0ul; i < USBD_MAX_EP; i++)
419                 {
420                     if(((USBD->EP[i].CFG & 0xFul) == epNum) && ((g_u32EpStallLock & (1ul << i)) == 0ul))
421                     {
422                         USBD->EP[i].CFGP &= ~USBD_CFGP_SSTALL_Msk;
423                         USBD->EP[i].CFG &= ~USBD_CFG_DSQSYNC_Msk;
424                     }
425                 }
426             }
427             else if(g_usbd_SetupPacket[2] == FEATURE_DEVICE_REMOTE_WAKEUP)
428             {
429                 g_usbd_RemoteWakeupEn = (uint8_t)0;
430             }
431 
432             /* Status stage */
433             USBD_SET_DATA1(EP0);
434             USBD_SET_PAYLOAD_LEN(EP0, 0ul);
435             break;
436         }
437         case SET_ADDRESS:
438         {
439             g_usbd_UsbAddr = g_usbd_SetupPacket[2];
440             /* Status Stage */
441             USBD_SET_DATA1(EP0);
442             USBD_SET_PAYLOAD_LEN(EP0, 0ul);
443 
444             break;
445         }
446         case SET_CONFIGURATION:
447         {
448             g_usbd_UsbConfig = g_usbd_SetupPacket[2];
449 
450             if(g_usbd_pfnSetConfigCallback)
451             {
452                 g_usbd_pfnSetConfigCallback();
453             }
454 
455             /* Status stage */
456             USBD_SET_DATA1(EP0);
457             USBD_SET_PAYLOAD_LEN(EP0, 0ul);
458             break;
459         }
460         case SET_FEATURE:
461         {
462             if( (g_usbd_SetupPacket[0] & 0xFul) == 0ul )   /* 0: device */
463             {
464                 if((g_usbd_SetupPacket[2] == 3ul) && (g_usbd_SetupPacket[3] == 0ul))   /* 3: HNP enable */
465                 {
466                     OTG->CTL |= (OTG_CTL_HNPREQEN_Msk | OTG_CTL_BUSREQ_Msk);
467                 }
468             }
469             if(g_usbd_SetupPacket[2] == FEATURE_ENDPOINT_HALT)
470             {
471                 USBD_SetStall((uint8_t)(g_usbd_SetupPacket[4] & 0xFul));
472             }
473             else if(g_usbd_SetupPacket[2] == FEATURE_DEVICE_REMOTE_WAKEUP)
474             {
475                 g_usbd_RemoteWakeupEn = (uint8_t)1ul;
476             }
477 
478             /* Status stage */
479             USBD_SET_DATA1(EP0);
480             USBD_SET_PAYLOAD_LEN(EP0, 0ul);
481 
482             break;
483         }
484         case SET_INTERFACE:
485         {
486             g_usbd_UsbAltInterface = g_usbd_SetupPacket[2];
487             if(g_usbd_pfnSetInterface != NULL)
488             {
489                 g_usbd_pfnSetInterface(g_usbd_UsbAltInterface);
490             }
491             /* Status stage */
492             USBD_SET_DATA1(EP0);
493             USBD_SET_PAYLOAD_LEN(EP0, 0ul);
494             break;
495         }
496         default:
497         {
498             /* Setup error, stall the device */
499             USBD_SET_EP_STALL(EP0);
500             USBD_SET_EP_STALL(EP1);
501             break;
502         }
503         }
504     }
505 }
506 
507 /**
508   * @brief      Prepare the first Control IN pipe
509   *
510   * @param[in]  pu8Buf  The pointer of data sent to USB host.
511   * @param[in]  u32Size The IN transfer size.
512   *
513   * @return     None
514   *
515   * @details    Prepare data for Control IN transfer.
516   *
517   */
USBD_PrepareCtrlIn(uint8_t pu8Buf[],uint32_t u32Size)518 void USBD_PrepareCtrlIn(uint8_t pu8Buf[], uint32_t u32Size)
519 {
520     uint32_t addr;
521     if(u32Size > g_usbd_CtrlMaxPktSize)
522     {
523         /* Data size > MXPLD */
524         g_usbd_CtrlInPointer = pu8Buf + g_usbd_CtrlMaxPktSize;
525         g_usbd_CtrlInSize = u32Size - g_usbd_CtrlMaxPktSize;
526         USBD_SET_DATA1(EP0);
527         addr = USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0);
528         USBD_MemCopy((uint8_t *)addr, pu8Buf, g_usbd_CtrlMaxPktSize);
529         USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlMaxPktSize);
530     }
531     else
532     {
533         /* Data size <= MXPLD */
534         g_usbd_CtrlInPointer = 0;
535         g_usbd_CtrlInSize = 0ul;
536         USBD_SET_DATA1(EP0);
537         addr = USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0);
538         USBD_MemCopy((uint8_t *)addr, pu8Buf, u32Size);
539         USBD_SET_PAYLOAD_LEN(EP0, u32Size);
540     }
541 }
542 
543 /**
544   * @brief    Repeat Control IN pipe
545   *
546   * @param    None
547   *
548   * @return   None
549   *
550   * @details  This function processes the remained data of Control IN transfer.
551   *
552   */
USBD_CtrlIn(void)553 void USBD_CtrlIn(void)
554 {
555     uint32_t addr;
556 
557     if(g_usbd_CtrlInSize)
558     {
559         /* Process remained data */
560         if(g_usbd_CtrlInSize > g_usbd_CtrlMaxPktSize)
561         {
562             /* Data size > MXPLD */
563             addr = USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0);
564             USBD_MemCopy((uint8_t *)addr, (uint8_t *)g_usbd_CtrlInPointer, g_usbd_CtrlMaxPktSize);
565             USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlMaxPktSize);
566             g_usbd_CtrlInPointer += g_usbd_CtrlMaxPktSize;
567             g_usbd_CtrlInSize -= g_usbd_CtrlMaxPktSize;
568         }
569         else
570         {
571             /* Data size <= MXPLD */
572             addr = USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0);
573             USBD_MemCopy((uint8_t *)addr, (uint8_t *)g_usbd_CtrlInPointer, g_usbd_CtrlInSize);
574             USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlInSize);
575             g_usbd_CtrlInPointer = 0;
576             g_usbd_CtrlInSize = 0ul;
577         }
578     }
579     else
580     {
581         /* In ACK for Set address */
582         if((g_usbd_SetupPacket[0] == REQ_STANDARD) && (g_usbd_SetupPacket[1] == SET_ADDRESS))
583         {
584             addr = USBD_GET_ADDR();
585             if((addr != g_usbd_UsbAddr) && (addr == 0ul))
586             {
587                 USBD_SET_ADDR(g_usbd_UsbAddr);
588             }
589         }
590 
591         /* For the case of data size is integral times maximum packet size */
592         if(g_usbd_CtrlInZeroFlag)
593         {
594             USBD_SET_PAYLOAD_LEN(EP0, 0ul);
595             g_usbd_CtrlInZeroFlag = (uint8_t)0ul;
596         }
597     }
598 }
599 
600 /**
601   * @brief      Prepare the first Control OUT pipe
602   *
603   * @param[in]  pu8Buf  The pointer of data received from USB host.
604   * @param[in]  u32Size The OUT transfer size.
605   *
606   * @return     None
607   *
608   * @details    This function is used to prepare the first Control OUT transfer.
609   *
610   */
USBD_PrepareCtrlOut(uint8_t * pu8Buf,uint32_t u32Size)611 void USBD_PrepareCtrlOut(uint8_t *pu8Buf, uint32_t u32Size)
612 {
613     g_usbd_CtrlOutPointer = pu8Buf;
614     g_usbd_CtrlOutSize = 0ul;
615     g_usbd_CtrlOutSizeLimit = u32Size;
616     USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
617 }
618 
619 /**
620   * @brief    Repeat Control OUT pipe
621   *
622   * @param    None
623   *
624   * @return   None
625   *
626   * @details  This function processes the successive Control OUT transfer.
627   *
628   */
USBD_CtrlOut(void)629 void USBD_CtrlOut(void)
630 {
631     uint32_t u32Size;
632     uint32_t addr;
633 
634     if (g_usbd_CtrlOutToggle != (USBD->EPSTS0 & USBD_EPSTS0_EPSTS1_Msk))
635     {
636         g_usbd_CtrlOutToggle = USBD->EPSTS0 & USBD_EPSTS0_EPSTS1_Msk;
637         if (g_usbd_CtrlOutSize < g_usbd_CtrlOutSizeLimit)
638         {
639             u32Size = USBD_GET_PAYLOAD_LEN(EP1);
640             addr = USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP1);
641             USBD_MemCopy((uint8_t *)g_usbd_CtrlOutPointer, (uint8_t *)addr, u32Size);
642             g_usbd_CtrlOutPointer += u32Size;
643             g_usbd_CtrlOutSize += u32Size;
644 
645             if(g_usbd_CtrlOutSize < g_usbd_CtrlOutSizeLimit)
646             {
647                 USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
648             }
649         }
650     }
651     else
652     {
653         USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
654     }
655 }
656 
657 /**
658   * @brief    Reset software flags
659   *
660   * @param    None
661   *
662   * @return   None
663   *
664   * @details  This function resets all variables for protocol and resets USB device address to 0.
665   *
666   */
USBD_SwReset(void)667 void USBD_SwReset(void)
668 {
669     uint32_t i;
670 
671     /* Reset all variables for protocol */
672     g_usbd_CtrlInPointer = 0;
673     g_usbd_CtrlInSize = 0ul;
674     g_usbd_CtrlOutPointer = 0;
675     g_usbd_CtrlOutSize = 0ul;
676     g_usbd_CtrlOutSizeLimit = 0ul;
677     g_u32EpStallLock = 0ul;
678     memset(g_usbd_SetupPacket, 0, 8ul);
679 
680     /* Reset PID DATA0 */
681     for(i=0ul; i<USBD_MAX_EP; i++)
682     {
683         USBD->EP[i].CFG &= ~USBD_CFG_DSQSYNC_Msk;
684     }
685 
686     /* Reset USB device address */
687     USBD_SET_ADDR(0ul);
688 }
689 
690 /**
691  * @brief       USBD Set Vendor Request
692  *
693  * @param[in]   pfnVendorReq    Vendor Request Callback Function
694  *
695  * @return      None
696  *
697  * @details     This function is used to set USBD vendor request callback function
698  */
USBD_SetVendorRequest(VENDOR_REQ pfnVendorReq)699 void USBD_SetVendorRequest(VENDOR_REQ pfnVendorReq)
700 {
701     g_usbd_pfnVendorRequest = pfnVendorReq;
702 }
703 
704 /**
705  * @brief       The callback function which called when get SET CONFIGURATION request
706  *
707  * @param[in]   pfnSetConfigCallback    Callback function pointer for SET CONFIGURATION request
708  *
709  * @return      None
710  *
711  * @details     This function is used to set the callback function which will be called at SET CONFIGURATION request.
712  */
USBD_SetConfigCallback(SET_CONFIG_CB pfnSetConfigCallback)713 void USBD_SetConfigCallback(SET_CONFIG_CB pfnSetConfigCallback)
714 {
715     g_usbd_pfnSetConfigCallback = pfnSetConfigCallback;
716 }
717 
718 
719 /**
720  * @brief       EP stall lock function to avoid stall clear by USB SET FEATURE request.
721  *
722  * @param[in]   u32EpBitmap    Use bitmap to select which endpoints will be locked
723  *
724  * @return      None
725  *
726  * @details     This function is used to lock relative endpoint to avoid stall clear by SET FEATURE request.
727  *              If ep stall locked, user needs to reset USB device or re-configure device to clear it.
728  */
USBD_LockEpStall(uint32_t u32EpBitmap)729 void USBD_LockEpStall(uint32_t u32EpBitmap)
730 {
731     g_u32EpStallLock = u32EpBitmap;
732 }
733 
734 
735 /*@}*/ /* end of group USBD_EXPORTED_FUNCTIONS */
736 
737 /*@}*/ /* end of group USBD_Driver */
738 
739 /*@}*/ /* end of group Standard_Driver */
740 
741 #ifdef __cplusplus
742 }
743 #endif
744 
745 /*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/
746