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