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