1 /**************************************************************************//**
2  * @file     hsusbd.c
3  * @version  V1.00
4  * @brief    M480 HSUSBD driver source file
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  * @copyright (C) 2016-2020 Nuvoton Technology Corp. All rights reserved.
8 *****************************************************************************/
9 #include <stdio.h>
10 #include "NuMicro.h"
11 
12 /** @addtogroup Standard_Driver Standard Driver
13   @{
14 */
15 
16 /** @addtogroup HSUSBD_Driver HSUSBD Driver
17   @{
18 */
19 
20 
21 /** @addtogroup HSUSBD_EXPORTED_FUNCTIONS HSUSBD Exported Functions
22   @{
23 */
24 /*--------------------------------------------------------------------------*/
25 /** @cond HIDDEN_SYMBOLS */
26 /* Global variables for Control Pipe */
27 S_HSUSBD_CMD_T gUsbCmd;
28 S_HSUSBD_INFO_T *g_hsusbd_sInfo;
29 
30 HSUSBD_VENDOR_REQ g_hsusbd_pfnVendorRequest = NULL;
31 HSUSBD_CLASS_REQ g_hsusbd_pfnClassRequest = NULL;
32 HSUSBD_SET_INTERFACE_REQ g_hsusbd_pfnSetInterface = NULL;
33 uint32_t g_u32HsEpStallLock = 0ul;       /* Bit map flag to lock specified EP when SET_FEATURE */
34 
35 static uint8_t *g_hsusbd_CtrlInPointer = 0;
36 static uint32_t g_hsusbd_CtrlMaxPktSize = 64ul;
37 static uint8_t g_hsusbd_UsbConfig = 0ul;
38 static uint8_t g_hsusbd_UsbAltInterface = 0ul;
39 static uint8_t g_hsusbd_EnableTestMode = 0ul;
40 static uint8_t g_hsusbd_TestSelector = 0ul;
41 
42 #ifdef __ICCARM__
43 #pragma data_alignment=4
44 static uint8_t g_hsusbd_buf[12];
45 #else
46 static uint8_t g_hsusbd_buf[12] __attribute__((aligned(4)));
47 #endif
48 
49 uint8_t volatile g_hsusbd_Configured = 0ul;
50 uint8_t g_hsusbd_CtrlZero = 0ul;
51 uint8_t g_hsusbd_UsbAddr = 0ul;
52 uint8_t g_hsusbd_ShortPacket = 0ul;
53 uint32_t volatile g_hsusbd_DmaDone = 0ul;
54 uint32_t g_hsusbd_CtrlInSize = 0ul;
55 /** @endcond HIDDEN_SYMBOLS */
56 
57 /**
58  * @brief       HSUSBD Initial
59  *
60  * @param[in]   param               Descriptor
61  * @param[in]   pfnClassReq         Class Request Callback Function
62  * @param[in]   pfnSetInterface     SetInterface Request Callback Function
63  *
64  * @return      None
65  *
66  * @details     This function is used to initial HSUSBD.
67  */
HSUSBD_Open(S_HSUSBD_INFO_T * param,HSUSBD_CLASS_REQ pfnClassReq,HSUSBD_SET_INTERFACE_REQ pfnSetInterface)68 void HSUSBD_Open(S_HSUSBD_INFO_T *param, HSUSBD_CLASS_REQ pfnClassReq, HSUSBD_SET_INTERFACE_REQ pfnSetInterface)
69 {
70     g_hsusbd_sInfo = param;
71     g_hsusbd_pfnClassRequest = pfnClassReq;
72     g_hsusbd_pfnSetInterface = pfnSetInterface;
73 
74     /* get EP0 maximum packet size */
75     g_hsusbd_CtrlMaxPktSize = g_hsusbd_sInfo->gu8DevDesc[7];
76 
77     /* Initial USB engine */
78     HSUSBD->PHYCTL |= (HSUSBD_PHYCTL_PHYEN_Msk | HSUSBD_PHYCTL_DPPUEN_Msk);
79     /* wait PHY clock ready */
80     while (1)
81     {
82         HSUSBD->EP[EPA].EPMPS = 0x20ul;
83         if (HSUSBD->EP[EPA].EPMPS == 0x20ul)
84         {
85             break;
86         }
87     }
88     /* Force SE0, and then clear it to connect*/
89     HSUSBD_SET_SE0();
90 }
91 
92 /**
93  * @brief       HSUSBD Start
94  *
95  * @param[in]   None
96  *
97  * @return      None
98  *
99  * @details     This function is used to start transfer
100  */
HSUSBD_Start(void)101 void HSUSBD_Start(void)
102 {
103     HSUSBD_CLR_SE0();
104 }
105 
106 /**
107  * @brief       Process Setup Packet
108  *
109  * @param[in]   None
110  *
111  * @return      None
112  *
113  * @details     This function is used to process Setup packet.
114  */
HSUSBD_ProcessSetupPacket(void)115 void HSUSBD_ProcessSetupPacket(void)
116 {
117     /* Setup packet process */
118     gUsbCmd.bmRequestType = (uint8_t)(HSUSBD->SETUP1_0 & 0xfful);
119     gUsbCmd.bRequest = (uint8_t)((HSUSBD->SETUP1_0 >> 8) & 0xfful);
120     gUsbCmd.wValue = (uint16_t)HSUSBD->SETUP3_2;
121     gUsbCmd.wIndex = (uint16_t)HSUSBD->SETUP5_4;
122     gUsbCmd.wLength = (uint16_t)HSUSBD->SETUP7_6;
123 
124     /* USB device request in setup packet: offset 0, D[6..5]: 0=Standard, 1=Class, 2=Vendor, 3=Reserved */
125     switch (gUsbCmd.bmRequestType & 0x60ul)
126     {
127     case REQ_STANDARD:
128     {
129         HSUSBD_StandardRequest();
130         break;
131     }
132     case REQ_CLASS:
133     {
134         if (g_hsusbd_pfnClassRequest != NULL)
135         {
136             g_hsusbd_pfnClassRequest();
137         }
138         break;
139     }
140     case REQ_VENDOR:
141     {
142         if (g_hsusbd_pfnVendorRequest != NULL)
143         {
144             g_hsusbd_pfnVendorRequest();
145         }
146         break;
147     }
148     default:
149     {
150         /* Setup error, stall the device */
151         HSUSBD_SET_CEP_STATE(HSUSBD_CEPCTL_STALLEN_Msk);
152         break;
153     }
154     }
155 }
156 
157 /**
158  * @brief       Get Descriptor request
159  *
160  * @param[in]   None
161  *
162  * @return      None
163  *
164  * @details     This function is used to process GetDescriptor request.
165  */
HSUSBD_GetDescriptor(void)166 int HSUSBD_GetDescriptor(void)
167 {
168     uint32_t u32Len;
169     int val = 0;
170 
171     u32Len = gUsbCmd.wLength;
172     g_hsusbd_CtrlZero = (uint8_t)0ul;
173 
174     switch ((gUsbCmd.wValue & 0xff00ul) >> 8)
175     {
176     /* Get Device Descriptor */
177     case DESC_DEVICE:
178     {
179         u32Len = Minimum(u32Len, LEN_DEVICE);
180         HSUSBD_PrepareCtrlIn((uint8_t *)g_hsusbd_sInfo->gu8DevDesc, u32Len);
181         break;
182     }
183     /* Get Configuration Descriptor */
184     case DESC_CONFIG:
185     {
186         uint32_t u32TotalLen;
187         if ((HSUSBD->OPER & 0x04ul) == 0x04ul)
188         {
189             u32TotalLen = g_hsusbd_sInfo->gu8ConfigDesc[3];
190             u32TotalLen = g_hsusbd_sInfo->gu8ConfigDesc[2] + (u32TotalLen << 8);
191 
192             if (u32Len > u32TotalLen)
193             {
194                 u32Len = u32TotalLen;
195                 if ((u32Len % g_hsusbd_CtrlMaxPktSize) == 0ul)
196                 {
197                     g_hsusbd_CtrlZero = (uint8_t)1ul;
198                 }
199             }
200             HSUSBD_PrepareCtrlIn((uint8_t *)g_hsusbd_sInfo->gu8ConfigDesc, u32Len);
201         }
202         else
203         {
204             u32TotalLen = g_hsusbd_sInfo->gu8FullConfigDesc[3];
205             u32TotalLen = g_hsusbd_sInfo->gu8FullConfigDesc[2] + (u32TotalLen << 8);
206 
207             if (u32Len > u32TotalLen)
208             {
209                 u32Len = u32TotalLen;
210                 if ((u32Len % g_hsusbd_CtrlMaxPktSize) == 0ul)
211                 {
212                     g_hsusbd_CtrlZero = (uint8_t)1ul;
213                 }
214             }
215             HSUSBD_PrepareCtrlIn((uint8_t *)g_hsusbd_sInfo->gu8FullConfigDesc, u32Len);
216         }
217 
218         break;
219     }
220     /* Get Qualifier Descriptor */
221     case DESC_QUALIFIER:
222     {
223         u32Len = Minimum(u32Len, LEN_QUALIFIER);
224         HSUSBD_PrepareCtrlIn((uint8_t *)g_hsusbd_sInfo->gu8QualDesc, u32Len);
225         break;
226     }
227     /* Get Other Speed Descriptor - Full speed */
228     case DESC_OTHERSPEED:
229     {
230         uint32_t u32TotalLen;
231         if ((HSUSBD->OPER & 0x04ul) == 0x04ul)
232         {
233             u32TotalLen = g_hsusbd_sInfo->gu8HSOtherConfigDesc[3];
234             u32TotalLen = g_hsusbd_sInfo->gu8HSOtherConfigDesc[2] + (u32TotalLen << 8);
235 
236             if (u32Len > u32TotalLen)
237             {
238                 u32Len = u32TotalLen;
239                 if ((u32Len % g_hsusbd_CtrlMaxPktSize) == 0ul)
240                 {
241                     g_hsusbd_CtrlZero = (uint8_t)1ul;
242                 }
243             }
244             HSUSBD_PrepareCtrlIn((uint8_t *)g_hsusbd_sInfo->gu8HSOtherConfigDesc, u32Len);
245         }
246         else
247         {
248             u32TotalLen = g_hsusbd_sInfo->gu8FSOtherConfigDesc[3];
249             u32TotalLen = g_hsusbd_sInfo->gu8FSOtherConfigDesc[2] + (u32TotalLen << 8);
250 
251             if (u32Len > u32TotalLen)
252             {
253                 u32Len = u32TotalLen;
254                 if ((u32Len % g_hsusbd_CtrlMaxPktSize) == 0ul)
255                 {
256                     g_hsusbd_CtrlZero = (uint8_t)1ul;
257                 }
258             }
259             HSUSBD_PrepareCtrlIn((uint8_t *)g_hsusbd_sInfo->gu8FSOtherConfigDesc, u32Len);
260         }
261 
262         break;
263     }
264     /* Get HID Descriptor */
265     case DESC_HID:
266     {
267         uint32_t u32ConfigDescOffset;   /* u32ConfigDescOffset is configuration descriptor offset (HID descriptor start index) */
268         u32Len = Minimum(u32Len, LEN_HID);
269         u32ConfigDescOffset = g_hsusbd_sInfo->gu32ConfigHidDescIdx[gUsbCmd.wIndex & 0xfful];
270         HSUSBD_PrepareCtrlIn((uint8_t *)&g_hsusbd_sInfo->gu8ConfigDesc[u32ConfigDescOffset], u32Len);
271         break;
272     }
273     /* Get Report Descriptor */
274     case DESC_HID_RPT:
275     {
276         if (u32Len > g_hsusbd_sInfo->gu32HidReportSize[gUsbCmd.wIndex & 0xfful])
277         {
278             u32Len = g_hsusbd_sInfo->gu32HidReportSize[gUsbCmd.wIndex & 0xfful];
279             if ((u32Len % g_hsusbd_CtrlMaxPktSize) == 0ul)
280             {
281                 g_hsusbd_CtrlZero = (uint8_t)1ul;
282             }
283         }
284         HSUSBD_PrepareCtrlIn((uint8_t *)g_hsusbd_sInfo->gu8HidReportDesc[gUsbCmd.wIndex & 0xfful], u32Len);
285         break;
286     }
287     /* Get String Descriptor */
288     case DESC_STRING:
289     {
290         if((gUsbCmd.wValue & 0xfful) < 8ul)
291         {
292             if (u32Len > g_hsusbd_sInfo->gu8StringDesc[gUsbCmd.wValue & 0xfful][0])
293             {
294                 u32Len = g_hsusbd_sInfo->gu8StringDesc[gUsbCmd.wValue & 0xfful][0];
295                 if ((u32Len % g_hsusbd_CtrlMaxPktSize) == 0ul)
296                 {
297                     g_hsusbd_CtrlZero = (uint8_t)1ul;
298                 }
299             }
300             HSUSBD_PrepareCtrlIn((uint8_t *)g_hsusbd_sInfo->gu8StringDesc[gUsbCmd.wValue & 0xfful], u32Len);
301         }
302         else
303         {
304             HSUSBD_SET_CEP_STATE(HSUSBD_CEPCTL_STALLEN_Msk);
305             val = 1;
306         }
307         break;
308     }
309     default:
310         /* Not support. Reply STALL. */
311         HSUSBD_SET_CEP_STATE(HSUSBD_CEPCTL_STALLEN_Msk);
312         val = 1;
313         break;
314     }
315     return val;
316 }
317 
318 
319 /**
320  * @brief       Process USB standard request
321  *
322  * @param[in]   None
323  *
324  * @return      None
325  *
326  * @details     This function is used to process USB Standard Request.
327  */
HSUSBD_StandardRequest(void)328 void HSUSBD_StandardRequest(void)
329 {
330     /* clear global variables for new request */
331     g_hsusbd_CtrlInPointer = 0;
332     g_hsusbd_CtrlInSize = 0ul;
333 
334     if ((gUsbCmd.bmRequestType & 0x80ul) == 0x80ul)   /* request data transfer direction */
335     {
336         /* Device to host */
337         switch (gUsbCmd.bRequest)
338         {
339         case GET_CONFIGURATION:
340         {
341             /* Return current configuration setting */
342             HSUSBD_PrepareCtrlIn((uint8_t *)&g_hsusbd_UsbConfig, 1ul);
343 
344             HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_INTKIF_Msk);
345             HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_INTKIEN_Msk);
346             break;
347         }
348         case GET_DESCRIPTOR:
349         {
350             if (!HSUSBD_GetDescriptor())
351             {
352                 HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_INTKIF_Msk);
353                 HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_INTKIEN_Msk);
354             }
355             break;
356         }
357         case GET_INTERFACE:
358         {
359             /* Return current interface setting */
360             HSUSBD_PrepareCtrlIn((uint8_t *)&g_hsusbd_UsbAltInterface, 1ul);
361 
362             HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_INTKIF_Msk);
363             HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_INTKIEN_Msk);
364             break;
365         }
366         case GET_STATUS:
367         {
368             /* Device */
369             if (gUsbCmd.bmRequestType == 0x80ul)
370             {
371                 if ((g_hsusbd_sInfo->gu8ConfigDesc[7] & 0x40ul) == 0x40ul)
372                 {
373                     g_hsusbd_buf[0] = (uint8_t)1ul; /* Self-Powered */
374                 }
375                 else
376                 {
377                     g_hsusbd_buf[0] = (uint8_t)0ul; /* bus-Powered */
378                 }
379             }
380             /* Interface */
381             else if (gUsbCmd.bmRequestType == 0x81ul)
382             {
383                 g_hsusbd_buf[0] = (uint8_t)0ul;
384             }
385             /* Endpoint */
386             else if (gUsbCmd.bmRequestType == 0x82ul)
387             {
388                 uint8_t ep = (uint8_t)(gUsbCmd.wIndex & 0xFul);
389                 g_hsusbd_buf[0] = (uint8_t)HSUSBD_GetStall((uint32_t)ep)? (uint8_t)1 : (uint8_t)0;
390             }
391             g_hsusbd_buf[1] = (uint8_t)0ul;
392             HSUSBD_PrepareCtrlIn(g_hsusbd_buf, 2ul);
393             HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_INTKIF_Msk);
394             HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_INTKIEN_Msk);
395             break;
396         }
397         default:
398         {
399             /* Setup error, stall the device */
400             HSUSBD_SET_CEP_STATE(HSUSBD_CEPCTL_STALLEN_Msk);
401             break;
402         }
403         }
404     }
405     else
406     {
407         /* Host to device */
408         switch (gUsbCmd.bRequest)
409         {
410         case CLEAR_FEATURE:
411         {
412             if((gUsbCmd.wValue & 0xfful) == FEATURE_ENDPOINT_HALT)
413             {
414 
415                 uint32_t epNum, i;
416 
417                 /* EP number stall is not allow to be clear in MSC class "Error Recovery Test".
418                    a flag: g_u32HsEpStallLock is added to support it */
419                 epNum = (uint32_t)(gUsbCmd.wIndex & 0xFul);
420                 for (i=0ul; i<HSUSBD_MAX_EP; i++)
421                 {
422                     if ((((HSUSBD->EP[i].EPCFG & 0xf0ul) >> 4) == epNum) && ((g_u32HsEpStallLock & (1ul << i)) == 0ul))
423                     {
424                         HSUSBD->EP[i].EPRSPCTL = (HSUSBD->EP[i].EPRSPCTL & 0xeful) | HSUSBD_EP_RSPCTL_TOGGLE;
425                     }
426                 }
427             }
428             /* Status stage */
429             HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_STSDONEIF_Msk);
430             HSUSBD_SET_CEP_STATE(HSUSBD_CEPCTL_NAKCLR);
431             HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_STSDONEIEN_Msk);
432             break;
433         }
434         case SET_ADDRESS:
435         {
436             g_hsusbd_UsbAddr = (uint8_t)gUsbCmd.wValue;
437             /* Status Stage */
438             HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_STSDONEIF_Msk);
439             HSUSBD_SET_CEP_STATE(HSUSBD_CEPCTL_NAKCLR);
440             HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_STSDONEIEN_Msk);
441             break;
442         }
443         case SET_CONFIGURATION:
444         {
445             g_hsusbd_UsbConfig = (uint8_t)gUsbCmd.wValue;
446             g_hsusbd_Configured = (uint8_t)1ul;
447             /* Status stage */
448             HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_STSDONEIF_Msk);
449             HSUSBD_SET_CEP_STATE(HSUSBD_CEPCTL_NAKCLR);
450             HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_STSDONEIEN_Msk);
451             break;
452         }
453         case SET_FEATURE:
454         {
455             if ((gUsbCmd.wValue & 0x3ul) == 2ul)    /* TEST_MODE */
456             {
457                 g_hsusbd_EnableTestMode = (uint8_t)1ul;
458                 g_hsusbd_TestSelector = (uint8_t)(gUsbCmd.wIndex >> 8);
459             }
460             if ((gUsbCmd.wValue & 0x3ul) == 3ul)    /* HNP ebable */
461             {
462                 HSOTG->CTL |= (HSOTG_CTL_HNPREQEN_Msk | HSOTG_CTL_BUSREQ_Msk);
463             }
464 
465             /* Status stage */
466             HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_STSDONEIF_Msk);
467             HSUSBD_SET_CEP_STATE(HSUSBD_CEPCTL_NAKCLR);
468             HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_STSDONEIEN_Msk);
469             break;
470         }
471         case SET_INTERFACE:
472         {
473             g_hsusbd_UsbAltInterface = (uint8_t)gUsbCmd.wValue;
474             if (g_hsusbd_pfnSetInterface != NULL)
475             {
476                 g_hsusbd_pfnSetInterface((uint32_t)g_hsusbd_UsbAltInterface);
477             }
478             /* Status stage */
479             HSUSBD_CLR_CEP_INT_FLAG(HSUSBD_CEPINTSTS_STSDONEIF_Msk);
480             HSUSBD_SET_CEP_STATE(HSUSBD_CEPCTL_NAKCLR);
481             HSUSBD_ENABLE_CEP_INT(HSUSBD_CEPINTEN_STSDONEIEN_Msk);
482             break;
483         }
484         default:
485         {
486             /* Setup error, stall the device */
487             HSUSBD_SET_CEP_STATE(HSUSBD_CEPCTL_STALLEN_Msk);
488             break;
489         }
490         }
491     }
492 }
493 
494 /**
495  * @brief       Update Device State
496  *
497  * @param[in]   None
498  *
499  * @return      None
500  *
501  * @details     This function is used to update Device state when Setup packet complete
502  */
503 /** @cond HIDDEN_SYMBOLS */
504 #define TEST_J                  0x01ul
505 #define TEST_K                  0x02ul
506 #define TEST_SE0_NAK            0x03ul
507 #define TEST_PACKET             0x04ul
508 #define TEST_FORCE_ENABLE       0x05ul
509 /** @endcond HIDDEN_SYMBOLS */
510 
HSUSBD_UpdateDeviceState(void)511 void HSUSBD_UpdateDeviceState(void)
512 {
513     switch (gUsbCmd.bRequest)
514     {
515     case SET_ADDRESS:
516     {
517         HSUSBD_SET_ADDR(g_hsusbd_UsbAddr);
518         break;
519     }
520     case SET_CONFIGURATION:
521     {
522         if (g_hsusbd_UsbConfig == 0ul)
523         {
524             uint32_t volatile i;
525             /* Reset PID DATA0 */
526             for (i=0ul; i<HSUSBD_MAX_EP; i++)
527             {
528                 if ((HSUSBD->EP[i].EPCFG & 0x1ul) == 0x1ul)
529                 {
530                     HSUSBD->EP[i].EPRSPCTL = HSUSBD_EP_RSPCTL_TOGGLE;
531                 }
532             }
533         }
534         break;
535     }
536     case SET_FEATURE:
537     {
538         if(gUsbCmd.wValue == FEATURE_ENDPOINT_HALT)
539         {
540             uint32_t idx;
541             idx = (uint32_t)(gUsbCmd.wIndex & 0xFul);
542             HSUSBD_SetStall(idx);
543         }
544         else if (g_hsusbd_EnableTestMode)
545         {
546             g_hsusbd_EnableTestMode = (uint8_t)0ul;
547             if (g_hsusbd_TestSelector == TEST_J)
548             {
549                 HSUSBD->TEST = TEST_J;
550             }
551             else if (g_hsusbd_TestSelector == TEST_K)
552             {
553                 HSUSBD->TEST = TEST_K;
554             }
555             else if (g_hsusbd_TestSelector == TEST_SE0_NAK)
556             {
557                 HSUSBD->TEST = TEST_SE0_NAK;
558             }
559             else if (g_hsusbd_TestSelector == TEST_PACKET)
560             {
561                 HSUSBD->TEST = TEST_PACKET;
562             }
563             else if (g_hsusbd_TestSelector == TEST_FORCE_ENABLE)
564             {
565                 HSUSBD->TEST = TEST_FORCE_ENABLE;
566             }
567         }
568         break;
569     }
570     case CLEAR_FEATURE:
571     {
572         if(gUsbCmd.wValue == FEATURE_ENDPOINT_HALT)
573         {
574             uint32_t idx;
575             idx = (uint32_t)(gUsbCmd.wIndex & 0xFul);
576             HSUSBD_ClearStall(idx);
577         }
578         break;
579     }
580     default:
581         break;
582     }
583 }
584 
585 
586 /**
587  * @brief       Prepare Control IN transaction
588  *
589  * @param[in]   pu8Buf      Control IN data pointer
590  * @param[in]   u32Size     IN transfer size
591  *
592  * @return      None
593  *
594  * @details     This function is used to prepare Control IN transfer
595  */
HSUSBD_PrepareCtrlIn(uint8_t pu8Buf[],uint32_t u32Size)596 void HSUSBD_PrepareCtrlIn(uint8_t pu8Buf[], uint32_t u32Size)
597 {
598     g_hsusbd_CtrlInPointer = pu8Buf;
599     g_hsusbd_CtrlInSize = u32Size;
600 }
601 
602 
603 
604 /**
605  * @brief       Start Control IN transfer
606  *
607  * @param[in]   None
608  *
609  * @return      None
610  *
611  * @details     This function is used to start Control IN
612  */
HSUSBD_CtrlIn(void)613 void HSUSBD_CtrlIn(void)
614 {
615     uint32_t volatile i, cnt;
616     uint8_t u8Value;
617     if(g_hsusbd_CtrlInSize >= g_hsusbd_CtrlMaxPktSize)
618     {
619         /* Data size > MXPLD */
620         cnt = g_hsusbd_CtrlMaxPktSize >> 2;
621         for (i=0ul; i<cnt; i++)
622         {
623             HSUSBD->CEPDAT = *(uint32_t *)g_hsusbd_CtrlInPointer;
624             g_hsusbd_CtrlInPointer = (uint8_t *)(g_hsusbd_CtrlInPointer + 4ul);
625         }
626         HSUSBD_START_CEP_IN(g_hsusbd_CtrlMaxPktSize);
627         g_hsusbd_CtrlInSize -= g_hsusbd_CtrlMaxPktSize;
628     }
629     else
630     {
631         /* Data size <= MXPLD */
632         cnt = g_hsusbd_CtrlInSize >> 2;
633         for (i=0ul; i<cnt; i++)
634         {
635             HSUSBD->CEPDAT = *(uint32_t *)g_hsusbd_CtrlInPointer;
636             g_hsusbd_CtrlInPointer += 4ul;
637         }
638 
639         for (i=0ul; i<(g_hsusbd_CtrlInSize % 4ul); i++)
640         {
641             u8Value = *(uint8_t *)(g_hsusbd_CtrlInPointer+i);
642             outpb(&HSUSBD->CEPDAT, u8Value);
643         }
644 
645         HSUSBD_START_CEP_IN(g_hsusbd_CtrlInSize);
646         g_hsusbd_CtrlInPointer = 0;
647         g_hsusbd_CtrlInSize = 0ul;
648     }
649 }
650 
651 /**
652  * @brief       Start Control OUT transaction
653  *
654  * @param[in]   pu8Buf      Control OUT data pointer
655  * @param[in]   u32Size     OUT transfer size
656  *
657  * @return      None
658  *
659  * @details     This function is used to start Control OUT transfer
660  */
HSUSBD_CtrlOut(uint8_t pu8Buf[],uint32_t u32Size)661 void HSUSBD_CtrlOut(uint8_t pu8Buf[], uint32_t u32Size)
662 {
663     uint32_t volatile i;
664     while(1)
665     {
666         if ((HSUSBD->CEPINTSTS & HSUSBD_CEPINTSTS_RXPKIF_Msk) == HSUSBD_CEPINTSTS_RXPKIF_Msk)
667         {
668             for (i=0ul; i<u32Size; i++)
669             {
670                 pu8Buf[i] = inpb(&HSUSBD->CEPDAT);
671             }
672             HSUSBD->CEPINTSTS = HSUSBD_CEPINTSTS_RXPKIF_Msk;
673             break;
674         }
675     }
676 }
677 
678 /**
679  * @brief       Clear all software flags
680  *
681  * @param[in]   None
682  *
683  * @return      None
684  *
685  * @details     This function is used to clear all software control flag
686  */
HSUSBD_SwReset(void)687 void HSUSBD_SwReset(void)
688 {
689     /* Reset all variables for protocol */
690     g_hsusbd_UsbAddr = (uint8_t)0ul;
691     g_hsusbd_DmaDone = 0ul;
692     g_hsusbd_ShortPacket = (uint8_t)0ul;
693     g_hsusbd_Configured = (uint8_t)0ul;
694 
695     /* Reset USB device address */
696     HSUSBD_SET_ADDR(0ul);
697 }
698 
699 /**
700  * @brief       HSUSBD Set Vendor Request
701  *
702  * @param[in]   pfnVendorReq         Vendor Request Callback Function
703  *
704  * @return      None
705  *
706  * @details     This function is used to set HSUSBD vendor request callback function
707  */
HSUSBD_SetVendorRequest(HSUSBD_VENDOR_REQ pfnVendorReq)708 void HSUSBD_SetVendorRequest(HSUSBD_VENDOR_REQ pfnVendorReq)
709 {
710     g_hsusbd_pfnVendorRequest = pfnVendorReq;
711 }
712 
713 
714 /*@}*/ /* end of group HSUSBD_EXPORTED_FUNCTIONS */
715 
716 /*@}*/ /* end of group HSUSBD_Driver */
717 
718 /*@}*/ /* end of group Standard_Driver */
719 
720 /*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/
721