M4521_BSP V3.02.000
The Board Support Package for M4521
usbd.c
Go to the documentation of this file.
1/**************************************************************************/
13#include <string.h>
14#include "M4521.h"
15
16#if 0
17#define DBG_PRINTF printf
18#else
19#define DBG_PRINTF(...)
20#endif
21
22#ifdef __cplusplus
23extern "C"
24{
25#endif
26
40/* Global variables for Control Pipe */
41uint8_t g_usbd_SetupPacket[8] = {0};
42volatile uint8_t g_usbd_RemoteWakeupEn = 0;
47static volatile uint8_t *g_usbd_CtrlInPointer = 0;
48static volatile uint32_t g_usbd_CtrlInSize = 0;
49static volatile uint8_t *g_usbd_CtrlOutPointer = 0;
50static volatile uint32_t g_usbd_CtrlOutSize = 0;
51static volatile uint32_t g_usbd_CtrlOutSizeLimit = 0;
52static volatile uint32_t g_usbd_UsbAddr = 0;
53static volatile uint32_t g_usbd_UsbConfig = 0;
54static volatile uint32_t g_usbd_CtrlMaxPktSize = 8;
55static volatile uint32_t g_usbd_UsbAltInterface = 0;
56static volatile uint32_t g_usbd_CtrlOutToggle = 0;
57static volatile uint8_t g_usbd_CtrlInZeroFlag = 0ul;
68uint32_t g_u32EpStallLock = 0;
81void USBD_Open(const S_USBD_INFO_T *param, CLASS_REQ pfnClassReq, SET_INTERFACE_REQ pfnSetInterface)
82{
83 g_usbd_sInfo = param;
84 g_usbd_pfnClassRequest = pfnClassReq;
85 g_usbd_pfnSetInterface = pfnSetInterface;
86
87 /* get EP0 maximum packet size */
88 g_usbd_CtrlMaxPktSize = g_usbd_sInfo->gu8DevDesc[7];
89
90 /* Initial USB engine */
91 USBD->ATTR = 0x7D0;
92 /* Force SE0 */
94}
95
105void USBD_Start(void)
106{
107 CLK_SysTickDelay(100000);
108 /* Disable software-disconnect function */
109 USBD_CLR_SE0();
110
111 /* Clear USB-related interrupts before enable interrupt */
113
114 /* Enable USB-related interrupts. */
116}
117
128void USBD_GetSetupPacket(uint8_t *buf)
129{
131}
132
144{
145 g_usbd_CtrlOutToggle = 0;
146 /* Get SETUP packet from USB buffer */
148 /* Check the request type */
149 switch(g_usbd_SetupPacket[0] & 0x60)
150 {
151 case REQ_STANDARD: // Standard
152 {
154 break;
155 }
156 case REQ_CLASS: // Class
157 {
159 {
161 }
162 break;
163 }
164 case REQ_VENDOR: // Vendor
165 {
167 {
169 }
170 break;
171 }
172 default: // reserved
173 {
174 /* Setup error, stall the device */
177 break;
178 }
179 }
180}
181
193{
194 uint32_t u32Len;
195
196 g_usbd_CtrlInZeroFlag = (uint8_t)0ul;
197 u32Len = 0;
198 u32Len = g_usbd_SetupPacket[7];
199 u32Len <<= 8;
200 u32Len += g_usbd_SetupPacket[6];
201
202 switch(g_usbd_SetupPacket[3])
203 {
204 // Get Device Descriptor
205 case DESC_DEVICE:
206 {
207 u32Len = Minimum(u32Len, LEN_DEVICE);
208 DBG_PRINTF("Get device desc, %d\n", u32Len);
209
210 USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8DevDesc, u32Len);
211
212 break;
213 }
214 // Get Configuration Descriptor
215 case DESC_CONFIG:
216 {
217 uint32_t u32TotalLen;
218
219 u32TotalLen = g_usbd_sInfo->gu8ConfigDesc[3];
220 u32TotalLen = g_usbd_sInfo->gu8ConfigDesc[2] + (u32TotalLen << 8);
221
222 if (u32Len > u32TotalLen)
223 {
224 u32Len = u32TotalLen;
225 if ((u32Len % g_usbd_CtrlMaxPktSize) == 0ul)
226 {
227 g_usbd_CtrlInZeroFlag = (uint8_t)1ul;
228 }
229 }
230 USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8ConfigDesc, u32Len);
231
232 break;
233 }
234 // Get HID Descriptor
235 case DESC_HID:
236 {
237 /* CV3.0 HID Class Descriptor Test,
238 Need to indicate index of the HID Descriptor within gu8ConfigDescriptor, specifically HID Composite device. */
239 uint32_t u32ConfigDescOffset; // u32ConfigDescOffset is configuration descriptor offset (HID descriptor start index)
240 u32Len = Minimum(u32Len, LEN_HID);
241 DBG_PRINTF("Get HID desc, %d\n", u32Len);
242
243 u32ConfigDescOffset = g_usbd_sInfo->gu32ConfigHidDescIdx[g_usbd_SetupPacket[4]];
244 USBD_PrepareCtrlIn((uint8_t *)&g_usbd_sInfo->gu8ConfigDesc[u32ConfigDescOffset], u32Len);
245
246 break;
247 }
248 // Get Report Descriptor
249 case DESC_HID_RPT:
250 {
252 {
254 if ((u32Len % g_usbd_CtrlMaxPktSize) == 0ul)
255 {
256 g_usbd_CtrlInZeroFlag = (uint8_t)1ul;
257 }
258 }
260 break;
261 }
262 // Get String Descriptor
263 case DESC_STRING:
264 {
265 // Get String Descriptor
266 if(g_usbd_SetupPacket[2] < 4)
267 {
268 if (u32Len > g_usbd_sInfo->gu8StringDesc[g_usbd_SetupPacket[2]][0])
269 {
271 if ((u32Len % g_usbd_CtrlMaxPktSize) == 0ul)
272 {
273 g_usbd_CtrlInZeroFlag = (uint8_t)1ul;
274 }
275 }
277
278
279 break;
280 }
281 else
282 {
283 // Not support. Reply STALL.
286
287 DBG_PRINTF("Unsupported string desc (%d). Stall ctrl pipe.\n", g_usbd_SetupPacket[2]);
288
289 break;
290 }
291 }
292 default:
293 // Not support. Reply STALL.
296
297 DBG_PRINTF("Unsupported get desc type. stall ctrl pipe\n");
298
299 break;
300 }
301}
302
314{
315
316 /* clear global variables for new request */
317 g_usbd_CtrlInPointer = 0;
318 g_usbd_CtrlInSize = 0;
319
320 if(g_usbd_SetupPacket[0] & 0x80) /* request data transfer direction */
321 {
322 // Device to host
323 switch(g_usbd_SetupPacket[1])
324 {
326 {
327 // Return current configuration setting
328 /* Data stage */
329 M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = g_usbd_UsbConfig;
332 /* Status stage */
334
335 DBG_PRINTF("Get configuration\n");
336
337 break;
338 }
339 case GET_DESCRIPTOR:
340 {
342 USBD_PrepareCtrlOut(0, 0); /* For status stage */
343 break;
344 }
345 case GET_INTERFACE:
346 {
347 // Return current interface setting
348 /* Data stage */
349 M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = g_usbd_UsbAltInterface;
352 /* Status stage */
354
355 DBG_PRINTF("Get interface\n");
356
357 break;
358 }
359 case GET_STATUS:
360 {
361 // Device
362 if(g_usbd_SetupPacket[0] == 0x80)
363 {
364 uint8_t u8Tmp;
365
366 u8Tmp = 0;
367 if(g_usbd_sInfo->gu8ConfigDesc[7] & 0x40) u8Tmp |= 1; // Self-Powered/Bus-Powered.
368 if(g_usbd_sInfo->gu8ConfigDesc[7] & 0x20) u8Tmp |= (g_usbd_RemoteWakeupEn << 1); // Remote wake up
369
371
372 }
373 // Interface
374 else if(g_usbd_SetupPacket[0] == 0x81)
376 // Endpoint
377 else if(g_usbd_SetupPacket[0] == 0x82)
378 {
379 uint8_t ep = g_usbd_SetupPacket[4] & 0xF;
381 }
382
384 /* Data stage */
387 /* Status stage */
389
390 DBG_PRINTF("Get status\n");
391
392 break;
393 }
394 default:
395 {
396 /* Setup error, stall the device */
399
400 DBG_PRINTF("Unknown request. stall ctrl pipe.\n");
401
402 break;
403 }
404 }
405 }
406 else
407 {
408 // Host to device
409 switch(g_usbd_SetupPacket[1])
410 {
411 case CLEAR_FEATURE:
412 {
414 {
415 int32_t epNum, i;
416
417 /* EP number stall is not allow to be clear in MSC class "Error Recovery Test".
418 a flag: g_u32EpStallLock is added to support it */
419 epNum = g_usbd_SetupPacket[4] & 0xF;
420 for(i = 0; i < USBD_MAX_EP; i++)
421 {
422 if(((USBD->EP[i].CFG & 0xF) == epNum) && ((g_u32EpStallLock & (1 << i)) == 0))
423 {
424 USBD->EP[i].CFGP &= ~USBD_CFGP_SSTALL_Msk;
425 USBD->EP[i].CFG &= ~USBD_CFG_DSQSYNC_Msk;
426 DBG_PRINTF("Clr stall ep%d %x\n", i, USBD->EP[i].CFGP);
427 }
428 }
429 }
432
433 /* Status stage */
436
437 DBG_PRINTF("Clear feature op %d\n", g_usbd_SetupPacket[2]);
438
439 break;
440 }
441 case SET_ADDRESS:
442 {
443 g_usbd_UsbAddr = g_usbd_SetupPacket[2];
444 DBG_PRINTF("Set addr to %d\n", g_usbd_UsbAddr);
445
446 // DATA IN for end of setup
447 /* Status Stage */
450
451 break;
452 }
454 {
455 g_usbd_UsbConfig = g_usbd_SetupPacket[2];
456
459
460 // DATA IN for end of setup
461 /* Status stage */
464
465 DBG_PRINTF("Set config to %d\n", g_usbd_UsbConfig);
466
467 break;
468 }
469 case SET_FEATURE:
470 {
472 {
474 DBG_PRINTF("Set feature. stall ep %d\n", g_usbd_SetupPacket[4] & 0xF);
475 }
477 {
479 DBG_PRINTF("Set feature. enable remote wakeup\n");
480 }
481
482 /* Status stage */
485
486
487
488 break;
489 }
490 case SET_INTERFACE:
491 {
492 g_usbd_UsbAltInterface = g_usbd_SetupPacket[2];
495 /* Status stage */
498
499 DBG_PRINTF("Set interface to %d\n", g_usbd_UsbAltInterface);
500
501 break;
502 }
503 default:
504 {
505 /* Setup error, stall the device */
508
509 DBG_PRINTF("Unsupported request. stall ctrl pipe.\n");
510
511 break;
512 }
513 }
514 }
515}
516
528void USBD_PrepareCtrlIn(uint8_t *pu8Buf, uint32_t u32Size)
529{
530 DBG_PRINTF("Prepare Ctrl In %d\n", u32Size);
531 if(u32Size > g_usbd_CtrlMaxPktSize)
532 {
533 // Data size > MXPLD
534 g_usbd_CtrlInPointer = pu8Buf + g_usbd_CtrlMaxPktSize;
535 g_usbd_CtrlInSize = u32Size - g_usbd_CtrlMaxPktSize;
537 USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), pu8Buf, g_usbd_CtrlMaxPktSize);
538 USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlMaxPktSize);
539 }
540 else
541 {
542 // Data size <= MXPLD
543 g_usbd_CtrlInPointer = 0;
544 g_usbd_CtrlInSize = 0;
546 USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), pu8Buf, u32Size);
547 USBD_SET_PAYLOAD_LEN(EP0, u32Size);
548 }
549}
550
561void USBD_CtrlIn(void)
562{
563 DBG_PRINTF("Ctrl In Ack. residue %d\n", g_usbd_CtrlInSize);
564 if(g_usbd_CtrlInSize)
565 {
566 // Process remained data
567 if(g_usbd_CtrlInSize > g_usbd_CtrlMaxPktSize)
568 {
569 // Data size > MXPLD
570 USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), (uint8_t *)g_usbd_CtrlInPointer, g_usbd_CtrlMaxPktSize);
571 USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlMaxPktSize);
572 g_usbd_CtrlInPointer += g_usbd_CtrlMaxPktSize;
573 g_usbd_CtrlInSize -= g_usbd_CtrlMaxPktSize;
574 }
575 else
576 {
577 // Data size <= MXPLD
578 USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), (uint8_t *)g_usbd_CtrlInPointer, g_usbd_CtrlInSize);
579 USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlInSize);
580 g_usbd_CtrlInPointer = 0;
581 g_usbd_CtrlInSize = 0;
582 }
583 }
584 else // No more data for IN token
585 {
586 // In ACK for Set address
588 {
589 if((USBD_GET_ADDR() != g_usbd_UsbAddr) && (USBD_GET_ADDR() == 0))
590 {
591 USBD_SET_ADDR(g_usbd_UsbAddr);
592 }
593 }
594
595 /* For the case of data size is integral times maximum packet size */
596 if(g_usbd_CtrlInZeroFlag)
597 {
599 g_usbd_CtrlInZeroFlag = (uint8_t)0ul;
600 }
601
602 DBG_PRINTF("Ctrl In done.\n");
603
604 }
605}
606
618void USBD_PrepareCtrlOut(uint8_t *pu8Buf, uint32_t u32Size)
619{
620 g_usbd_CtrlOutPointer = pu8Buf;
621 g_usbd_CtrlOutSize = 0;
622 g_usbd_CtrlOutSizeLimit = u32Size;
623 USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
624}
625
636void USBD_CtrlOut(void)
637{
638 uint32_t u32Size;
639
640 DBG_PRINTF("Ctrl Out Ack %d\n", g_usbd_CtrlOutSize);
641
642 if (g_usbd_CtrlOutToggle != (USBD->EPSTS & USBD_EPSTS_EPSTS1_Msk))
643 {
644 g_usbd_CtrlOutToggle = USBD->EPSTS & USBD_EPSTS_EPSTS1_Msk;
645 if(g_usbd_CtrlOutSize < g_usbd_CtrlOutSizeLimit)
646 {
647 u32Size = USBD_GET_PAYLOAD_LEN(EP1);
648 USBD_MemCopy((uint8_t *)g_usbd_CtrlOutPointer, (uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP1), u32Size);
649 g_usbd_CtrlOutPointer += u32Size;
650 g_usbd_CtrlOutSize += u32Size;
651
652 if(g_usbd_CtrlOutSize < g_usbd_CtrlOutSizeLimit)
653 USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
654 }
655 }
656 else
657 {
658 USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
659 }
660}
661
672void USBD_SwReset(void)
673{
674 int i;
675
676 // Reset all variables for protocol
677 g_usbd_CtrlInPointer = 0;
678 g_usbd_CtrlInSize = 0;
679 g_usbd_CtrlOutPointer = 0;
680 g_usbd_CtrlOutSize = 0;
681 g_usbd_CtrlOutSizeLimit = 0;
683 memset(g_usbd_SetupPacket, 0, 8);
684
685 /* Reset PID DATA0 */
686 for(i=0; i<USBD_MAX_EP; i++)
687 USBD->EP[i].CFG &= ~USBD_CFG_DSQSYNC_Msk;
688
689 // Reset USB device address
690 USBD_SET_ADDR(0);
691}
692
703{
704 g_usbd_pfnVendorRequest = pfnVendorReq;
705}
706
716void USBD_SetConfigCallback(SET_CONFIG_CB pfnSetConfigCallback)
717{
718 g_usbd_pfnSetConfigCallback = pfnSetConfigCallback;
719}
720
721
732void USBD_LockEpStall(uint32_t u32EpBitmap)
733{
734 g_u32EpStallLock = u32EpBitmap;
735}
736
737
738
739
740 /* end of group USBD_EXPORTED_FUNCTIONS */
742 /* end of group USBD_Driver */
744 /* end of group Standard_Driver */
746
747#ifdef __cplusplus
748}
749#endif
750
751/*** (C) COPYRIGHT 2022 Nuvoton Technology Corp. ***/
#define USBD_EPSTS_EPSTS1_Msk
Definition: M4521.h:12604
#define USBD_CFG_DSQSYNC_Msk
Definition: M4521.h:12679
__STATIC_INLINE int32_t CLK_SysTickDelay(uint32_t us)
This function execute delay function.
Definition: clk.h:373
#define NULL
Definition: M4521.h:13912
#define M8(adr)
Definition: M4521.h:13939
#define USBD
Definition: M4521.h:13841
#define GET_DESCRIPTOR
Definition: usbd.h:70
#define LEN_HID
Definition: usbd.h:96
#define GET_INTERFACE
Definition: usbd.h:74
#define CLEAR_FEATURE
Definition: usbd.h:67
#define LEN_DEVICE
Definition: usbd.h:92
#define REQ_STANDARD
Definition: usbd.h:61
#define USBD_INT_FLDET
Definition: usbd.h:125
#define DESC_HID
Definition: usbd.h:88
#define REQ_CLASS
Definition: usbd.h:62
#define USBD_INT_WAKEUP
Definition: usbd.h:126
#define SET_CONFIGURATION
Definition: usbd.h:73
#define DESC_HID_RPT
Definition: usbd.h:89
#define DESC_DEVICE
Definition: usbd.h:79
#define USBD_MAX_EP
Definition: usbd.h:48
#define USBD_BUF_BASE
Definition: usbd.h:47
#define REQ_VENDOR
Definition: usbd.h:63
#define USBD_INT_BUS
Definition: usbd.h:123
#define SET_INTERFACE
Definition: usbd.h:75
#define EP1
Definition: usbd.h:51
#define FEATURE_DEVICE_REMOTE_WAKEUP
Definition: usbd.h:108
#define DESC_CONFIG
Definition: usbd.h:80
#define USBD_INT_USB
Definition: usbd.h:124
#define GET_CONFIGURATION
Definition: usbd.h:72
#define SET_ADDRESS
Definition: usbd.h:69
#define FEATURE_ENDPOINT_HALT
Definition: usbd.h:109
#define EP0
Definition: usbd.h:50
#define DESC_STRING
Definition: usbd.h:81
#define GET_STATUS
Definition: usbd.h:66
#define SET_FEATURE
Definition: usbd.h:68
void USBD_Open(const S_USBD_INFO_T *param, CLASS_REQ pfnClassReq, SET_INTERFACE_REQ pfnSetInterface)
This function makes USBD module to be ready to use.
Definition: usbd.c:81
#define USBD_GET_EP_BUF_ADDR(ep)
Get the offset of the specified USB endpoint buffer.
Definition: usbd.h:471
void USBD_LockEpStall(uint32_t u32EpBitmap)
EP stall lock function to avoid stall clear by USB SET FEATURE request.
Definition: usbd.c:732
void USBD_StandardRequest(void)
Process standard request.
Definition: usbd.c:313
const uint32_t * gu32ConfigHidDescIdx
Definition: usbd.h:33
#define USBD_SET_SE0()
Enable SE0. Force USB PHY transceiver to drive SE0.
Definition: usbd.h:248
#define USBD_GET_PAYLOAD_LEN(ep)
Get USB payload size (OUT data)
Definition: usbd.h:431
void(* VENDOR_REQ)(void)
Definition: usbd.h:628
#define USBD_SET_DATA1(ep)
Set USB DATA1 PID for the specified endpoint ID.
Definition: usbd.h:392
CLASS_REQ g_usbd_pfnClassRequest
Definition: usbd.c:65
volatile uint8_t g_usbd_RemoteWakeupEn
Definition: usbd.c:42
void USBD_PrepareCtrlOut(uint8_t *pu8Buf, uint32_t u32Size)
Prepare the first Control OUT pipe.
Definition: usbd.c:618
static __INLINE void USBD_SetStall(uint8_t epnum)
Set USB endpoint stall state.
Definition: usbd.h:539
#define USBD_GET_ADDR()
Get USB device address.
Definition: usbd.h:284
static __INLINE uint32_t USBD_GetStall(uint8_t epnum)
Get USB endpoint stall state.
Definition: usbd.h:603
void USBD_GetDescriptor(void)
Process GetDescriptor request.
Definition: usbd.c:192
#define USBD_SET_ADDR(addr)
Set USB device address.
Definition: usbd.h:272
void USBD_GetSetupPacket(uint8_t *buf)
Get the received SETUP packet.
Definition: usbd.c:128
void(* CLASS_REQ)(void)
Definition: usbd.h:629
SET_INTERFACE_REQ g_usbd_pfnSetInterface
Definition: usbd.c:66
#define USBD_CLR_SE0()
Disable SE0.
Definition: usbd.h:260
void USBD_Start(void)
This function makes USB host to recognize the device.
Definition: usbd.c:105
void USBD_SwReset(void)
Reset software flags.
Definition: usbd.c:672
void USBD_PrepareCtrlIn(uint8_t *pu8Buf, uint32_t u32Size)
Prepare the first Control IN pipe.
Definition: usbd.c:528
void USBD_CtrlIn(void)
Repeat Control IN pipe.
Definition: usbd.c:561
uint32_t g_u32EpStallLock
Definition: usbd.c:68
uint8_t g_usbd_SetupPacket[8]
Definition: usbd.c:41
#define Minimum(a, b)
Compare two input numbers and return minimum one.
Definition: usbd.h:187
void USBD_SetConfigCallback(SET_CONFIG_CB pfnSetConfigCallback)
The callback function which called when get SET CONFIGURATION request.
Definition: usbd.c:716
static __INLINE void USBD_MemCopy(uint8_t *dest, uint8_t *src, int32_t size)
To support byte access between USB SRAM and system SRAM.
Definition: usbd.h:523
const S_USBD_INFO_T * g_usbd_sInfo
Definition: usbd.c:62
#define USBD_SET_EP_STALL(ep)
Set USB endpoint stall state.
Definition: usbd.h:483
void USBD_SetVendorRequest(VENDOR_REQ pfnVendorReq)
USBD Set Vendor Request.
Definition: usbd.c:702
void USBD_ProcessSetupPacket(void)
Process SETUP packet.
Definition: usbd.c:143
#define USBD_CLR_INT_FLAG(flag)
Clear USB interrupt flag.
Definition: usbd.h:326
SET_CONFIG_CB g_usbd_pfnSetConfigCallback
Definition: usbd.c:67
void(* SET_INTERFACE_REQ)(void)
Definition: usbd.h:630
const uint8_t * gu8ConfigDesc
Definition: usbd.h:29
const uint8_t * gu8DevDesc
Definition: usbd.h:28
const uint32_t * gu32HidReportSize
Definition: usbd.h:32
void(* SET_CONFIG_CB)(void)
Definition: usbd.h:631
const uint8_t ** gu8HidReportDesc
Definition: usbd.h:31
void USBD_CtrlOut(void)
Repeat Control OUT pipe.
Definition: usbd.c:636
const uint8_t ** gu8StringDesc
Definition: usbd.h:30
#define USBD_ENABLE_INT(intr)
Enable USB interrupt function.
Definition: usbd.h:299
VENDOR_REQ g_usbd_pfnVendorRequest
Definition: usbd.c:64
#define USBD_SET_PAYLOAD_LEN(ep, size)
Set USB payload size (IN data)
Definition: usbd.h:419
#define DBG_PRINTF(...)
Definition: usbd.c:19