M480 BSP  V3.05.001
The Board Support Package for M480 Series
usbd.c
Go to the documentation of this file.
1 /**************************************************************************/
10 #include <string.h>
11 #include "NuMicro.h"
12 
13 #ifdef __cplusplus
14 extern "C"
15 {
16 #endif
17 
31 /* Global variables for Control Pipe */
32 uint8_t g_usbd_SetupPacket[8] = {0ul};
33 volatile uint8_t g_usbd_RemoteWakeupEn = 0ul;
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;
59 uint32_t g_u32EpStallLock = 0ul;
72 void USBD_Open(const S_USBD_INFO_T *param, CLASS_REQ pfnClassReq, SET_INTERFACE_REQ pfnSetInterface)
73 {
74  g_usbd_sInfo = param;
75  g_usbd_pfnClassRequest = pfnClassReq;
76  g_usbd_pfnSetInterface = pfnSetInterface;
77 
78  /* get EP0 maximum packet size */
79  g_usbd_CtrlMaxPktSize = g_usbd_sInfo->gu8DevDesc[7];
80 
81  /* Initial USB engine */
82  USBD->ATTR = 0x6D0ul;
83  /* Force SE0 */
84  USBD_SET_SE0();
85 }
86 
96 void USBD_Start(void)
97 {
98  /* Disable software-disconnect function */
99  USBD_CLR_SE0();
100  USBD->ATTR = 0x7D0ul;
101 
102  /* Clear USB-related interrupts before enable interrupt */
104 
105  /* Enable USB-related interrupts. */
107 }
108 
119 void USBD_GetSetupPacket(uint8_t *buf)
120 {
121  USBD_MemCopy(buf, g_usbd_SetupPacket, 8ul);
122 }
123 
135 {
136  g_usbd_CtrlOutToggle = 0;
137  /* Get SETUP packet from USB buffer */
139 
140  /* Check the request type */
141  switch(g_usbd_SetupPacket[0] & 0x60ul)
142  {
143  case REQ_STANDARD:
144  {
146  break;
147  }
148  case REQ_CLASS:
149  {
151  {
153  }
154  break;
155  }
156  case REQ_VENDOR:
157  {
159  {
161  }
162  break;
163  }
164  default:
165  {
166  /* Setup error, stall the device */
169  break;
170  }
171  }
172 }
173 
185 {
186  uint32_t u32Len;
187 
188  g_usbd_CtrlInZeroFlag = (uint8_t)0ul;
189  u32Len = 0ul;
190  u32Len = g_usbd_SetupPacket[7];
191  u32Len <<= 8ul;
192  u32Len += g_usbd_SetupPacket[6];
193 
194  switch(g_usbd_SetupPacket[3])
195  {
196  /* Get Device Descriptor */
197  case DESC_DEVICE:
198  {
199  u32Len = USBD_Minimum(u32Len, (uint32_t)LEN_DEVICE);
200  USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8DevDesc, u32Len);
201 
202  break;
203  }
204  /* Get Configuration Descriptor */
205  case DESC_CONFIG:
206  {
207  uint32_t u32TotalLen;
208 
209  u32TotalLen = g_usbd_sInfo->gu8ConfigDesc[3];
210  u32TotalLen = g_usbd_sInfo->gu8ConfigDesc[2] + (u32TotalLen << 8);
211 
212  if (u32Len > u32TotalLen)
213  {
214  u32Len = u32TotalLen;
215  if ((u32Len % g_usbd_CtrlMaxPktSize) == 0ul)
216  {
217  g_usbd_CtrlInZeroFlag = (uint8_t)1ul;
218  }
219  }
220  USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8ConfigDesc, u32Len);
221 
222  break;
223  }
224 
225  /* Get BOS Descriptor */
226  case DESC_BOS:
227  {
228  if (g_usbd_sInfo->gu8BosDesc == 0)
229  {
232  }
233  else
234  {
235  u32Len = USBD_Minimum(u32Len, LEN_BOS+LEN_BOSCAP);
236  USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8BosDesc, u32Len);
237  }
238  break;
239  }
240  /* Get HID Descriptor */
241  case DESC_HID:
242  {
243  /* CV3.0 HID Class Descriptor Test,
244  Need to indicate index of the HID Descriptor within gu8ConfigDescriptor, specifically HID Composite device. */
245  uint32_t u32ConfigDescOffset; /* u32ConfigDescOffset is configuration descriptor offset (HID descriptor start index) */
246  u32Len = USBD_Minimum(u32Len, LEN_HID);
247  u32ConfigDescOffset = g_usbd_sInfo->gu32ConfigHidDescIdx[g_usbd_SetupPacket[4]];
248  USBD_PrepareCtrlIn((uint8_t *)&g_usbd_sInfo->gu8ConfigDesc[u32ConfigDescOffset], u32Len);
249 
250  break;
251  }
252  /* Get Report Descriptor */
253  case DESC_HID_RPT:
254  {
256  {
258  if ((u32Len % g_usbd_CtrlMaxPktSize) == 0ul)
259  {
260  g_usbd_CtrlInZeroFlag = (uint8_t)1ul;
261  }
262  }
264  break;
265  }
266  /* Get String Descriptor */
267  case DESC_STRING:
268  {
269  /* Get String Descriptor */
270  if(g_usbd_SetupPacket[2] < 4ul)
271  {
272  if (u32Len > g_usbd_sInfo->gu8StringDesc[g_usbd_SetupPacket[2]][0])
273  {
275  if ((u32Len % g_usbd_CtrlMaxPktSize) == 0ul)
276  {
277  g_usbd_CtrlInZeroFlag = (uint8_t)1ul;
278  }
279  }
281  break;
282  }
283  else
284  {
285  /* Not support. Reply STALL. */
288  break;
289  }
290  }
291  default:
292  /* Not support. Reply STALL.*/
295  break;
296  }
297 }
298 
310 {
311  uint32_t addr;
312  /* clear global variables for new request */
313  g_usbd_CtrlInPointer = 0;
314  g_usbd_CtrlInSize = 0ul;
315 
316  if((g_usbd_SetupPacket[0] & 0x80ul) == 0x80ul) /* request data transfer direction */
317  {
318  /* Device to host */
319  switch(g_usbd_SetupPacket[1])
320  {
321  case GET_CONFIGURATION:
322  {
323  /* Return current configuration setting */
324  /* Data stage */
326  M8(addr) = (uint8_t)g_usbd_UsbConfig;
329  /* Status stage */
330  USBD_PrepareCtrlOut(0, 0ul);
331  break;
332  }
333  case GET_DESCRIPTOR:
334  {
336  USBD_PrepareCtrlOut(0, 0ul); /* For status stage */
337  break;
338  }
339  case GET_INTERFACE:
340  {
341  /* Return current interface setting */
342  /* Data stage */
344  M8(addr) = (uint8_t)g_usbd_UsbAltInterface;
347  /* Status stage */
348  USBD_PrepareCtrlOut(0, 0ul);
349  break;
350  }
351  case GET_STATUS:
352  {
353  /* Device */
354  if(g_usbd_SetupPacket[0] == 0x80ul)
355  {
356  uint8_t u8Tmp;
357 
358  u8Tmp = (uint8_t)0ul;
359  if ((g_usbd_sInfo->gu8ConfigDesc[7] & 0x40ul) == 0x40ul)
360  {
361  u8Tmp |= (uint8_t)1ul; /* Self-Powered/Bus-Powered.*/
362  }
363  if ((g_usbd_sInfo->gu8ConfigDesc[7] & 0x20ul) == 0x20ul)
364  {
365  u8Tmp |= (uint8_t)(g_usbd_RemoteWakeupEn << 1ul); /* Remote wake up */
366  }
367 
369  M8(addr) = u8Tmp;
370 
371  }
372  /* Interface */
373  else if(g_usbd_SetupPacket[0] == 0x81ul)
374  {
376  M8(addr) = (uint8_t)0ul;
377  }
378  /* Endpoint */
379  else if(g_usbd_SetupPacket[0] == 0x82ul)
380  {
381  uint8_t ep = (uint8_t)(g_usbd_SetupPacket[4] & 0xFul);
383  M8(addr) = (uint8_t)(USBD_GetStall(ep) ? 1ul : 0ul);
384  }
385 
386  addr = USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0) + 1ul;
387  M8(addr) = (uint8_t)0ul;
388  /* Data stage */
391  /* Status stage */
392  USBD_PrepareCtrlOut(0, 0ul);
393  break;
394  }
395  default:
396  {
397  /* Setup error, stall the device */
400  break;
401  }
402  }
403  }
404  else
405  {
406  /* Host to device */
407  switch(g_usbd_SetupPacket[1])
408  {
409  case CLEAR_FEATURE:
410  {
411  if(g_usbd_SetupPacket[2] == FEATURE_ENDPOINT_HALT)
412  {
413  uint32_t epNum, i;
414 
415  /* EP number stall is not allow to be clear in MSC class "Error Recovery Test".
416  a flag: g_u32EpStallLock is added to support it */
417  epNum = (uint8_t)(g_usbd_SetupPacket[4] & 0xFul);
418  for(i = 0ul; i < USBD_MAX_EP; i++)
419  {
420  if(((USBD->EP[i].CFG & 0xFul) == epNum) && ((g_u32EpStallLock & (1ul << i)) == 0ul))
421  {
422  USBD->EP[i].CFGP &= ~USBD_CFGP_SSTALL_Msk;
423  USBD->EP[i].CFG &= ~USBD_CFG_DSQSYNC_Msk;
424  }
425  }
426  }
427  else if(g_usbd_SetupPacket[2] == FEATURE_DEVICE_REMOTE_WAKEUP)
428  {
429  g_usbd_RemoteWakeupEn = (uint8_t)0;
430  }
431 
432  /* Status stage */
435  break;
436  }
437  case SET_ADDRESS:
438  {
439  g_usbd_UsbAddr = g_usbd_SetupPacket[2];
440  /* Status Stage */
443 
444  break;
445  }
446  case SET_CONFIGURATION:
447  {
448  g_usbd_UsbConfig = g_usbd_SetupPacket[2];
449 
451  {
453  }
454 
455  /* Status stage */
458  break;
459  }
460  case SET_FEATURE:
461  {
462  if( (g_usbd_SetupPacket[0] & 0xFul) == 0ul ) /* 0: device */
463  {
464  if((g_usbd_SetupPacket[2] == 3ul) && (g_usbd_SetupPacket[3] == 0ul)) /* 3: HNP enable */
465  {
467  }
468  }
469  if(g_usbd_SetupPacket[2] == FEATURE_ENDPOINT_HALT)
470  {
471  USBD_SetStall((uint8_t)(g_usbd_SetupPacket[4] & 0xFul));
472  }
473  else if(g_usbd_SetupPacket[2] == FEATURE_DEVICE_REMOTE_WAKEUP)
474  {
475  g_usbd_RemoteWakeupEn = (uint8_t)1ul;
476  }
477 
478  /* Status stage */
481 
482  break;
483  }
484  case SET_INTERFACE:
485  {
486  g_usbd_UsbAltInterface = g_usbd_SetupPacket[2];
488  {
489  g_usbd_pfnSetInterface(g_usbd_UsbAltInterface);
490  }
491  /* Status stage */
494  break;
495  }
496  default:
497  {
498  /* Setup error, stall the device */
501  break;
502  }
503  }
504  }
505 }
506 
518 void USBD_PrepareCtrlIn(uint8_t pu8Buf[], uint32_t u32Size)
519 {
520  uint32_t addr;
521  if(u32Size > g_usbd_CtrlMaxPktSize)
522  {
523  /* Data size > MXPLD */
524  g_usbd_CtrlInPointer = pu8Buf + g_usbd_CtrlMaxPktSize;
525  g_usbd_CtrlInSize = u32Size - g_usbd_CtrlMaxPktSize;
528  USBD_MemCopy((uint8_t *)addr, pu8Buf, g_usbd_CtrlMaxPktSize);
529  USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlMaxPktSize);
530  }
531  else
532  {
533  /* Data size <= MXPLD */
534  g_usbd_CtrlInPointer = 0;
535  g_usbd_CtrlInSize = 0ul;
538  USBD_MemCopy((uint8_t *)addr, pu8Buf, u32Size);
539  USBD_SET_PAYLOAD_LEN(EP0, u32Size);
540  }
541 }
542 
553 void USBD_CtrlIn(void)
554 {
555  uint32_t addr;
556 
557  if(g_usbd_CtrlInSize)
558  {
559  /* Process remained data */
560  if(g_usbd_CtrlInSize > g_usbd_CtrlMaxPktSize)
561  {
562  /* Data size > MXPLD */
564  USBD_MemCopy((uint8_t *)addr, (uint8_t *)g_usbd_CtrlInPointer, g_usbd_CtrlMaxPktSize);
565  USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlMaxPktSize);
566  g_usbd_CtrlInPointer += g_usbd_CtrlMaxPktSize;
567  g_usbd_CtrlInSize -= g_usbd_CtrlMaxPktSize;
568  }
569  else
570  {
571  /* Data size <= MXPLD */
573  USBD_MemCopy((uint8_t *)addr, (uint8_t *)g_usbd_CtrlInPointer, g_usbd_CtrlInSize);
574  USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlInSize);
575  g_usbd_CtrlInPointer = 0;
576  g_usbd_CtrlInSize = 0ul;
577  }
578  }
579  else
580  {
581  /* In ACK for Set address */
582  if((g_usbd_SetupPacket[0] == REQ_STANDARD) && (g_usbd_SetupPacket[1] == SET_ADDRESS))
583  {
584  addr = USBD_GET_ADDR();
585  if((addr != g_usbd_UsbAddr) && (addr == 0ul))
586  {
587  USBD_SET_ADDR(g_usbd_UsbAddr);
588  }
589  }
590 
591  /* For the case of data size is integral times maximum packet size */
592  if(g_usbd_CtrlInZeroFlag)
593  {
595  g_usbd_CtrlInZeroFlag = (uint8_t)0ul;
596  }
597  }
598 }
599 
611 void USBD_PrepareCtrlOut(uint8_t *pu8Buf, uint32_t u32Size)
612 {
613  g_usbd_CtrlOutPointer = pu8Buf;
614  g_usbd_CtrlOutSize = 0ul;
615  g_usbd_CtrlOutSizeLimit = u32Size;
616  USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
617 }
618 
629 void USBD_CtrlOut(void)
630 {
631  uint32_t u32Size;
632  uint32_t addr;
633 
634  if (g_usbd_CtrlOutToggle != (USBD->EPSTS0 & USBD_EPSTS0_EPSTS1_Msk))
635  {
636  g_usbd_CtrlOutToggle = USBD->EPSTS0 & USBD_EPSTS0_EPSTS1_Msk;
637  if (g_usbd_CtrlOutSize < g_usbd_CtrlOutSizeLimit)
638  {
639  u32Size = USBD_GET_PAYLOAD_LEN(EP1);
641  USBD_MemCopy((uint8_t *)g_usbd_CtrlOutPointer, (uint8_t *)addr, u32Size);
642  g_usbd_CtrlOutPointer += u32Size;
643  g_usbd_CtrlOutSize += u32Size;
644 
645  if(g_usbd_CtrlOutSize < g_usbd_CtrlOutSizeLimit)
646  {
647  USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
648  }
649  }
650  }
651  else
652  {
653  USBD_SET_PAYLOAD_LEN(EP1, g_usbd_CtrlMaxPktSize);
654  }
655 }
656 
667 void USBD_SwReset(void)
668 {
669  uint32_t i;
670 
671  /* Reset all variables for protocol */
672  g_usbd_CtrlInPointer = 0;
673  g_usbd_CtrlInSize = 0ul;
674  g_usbd_CtrlOutPointer = 0;
675  g_usbd_CtrlOutSize = 0ul;
676  g_usbd_CtrlOutSizeLimit = 0ul;
677  g_u32EpStallLock = 0ul;
678  memset(g_usbd_SetupPacket, 0, 8ul);
679 
680  /* Reset PID DATA0 */
681  for(i=0ul; i<USBD_MAX_EP; i++)
682  {
683  USBD->EP[i].CFG &= ~USBD_CFG_DSQSYNC_Msk;
684  }
685 
686  /* Reset USB device address */
687  USBD_SET_ADDR(0ul);
688 }
689 
700 {
701  g_usbd_pfnVendorRequest = pfnVendorReq;
702 }
703 
713 void USBD_SetConfigCallback(SET_CONFIG_CB pfnSetConfigCallback)
714 {
715  g_usbd_pfnSetConfigCallback = pfnSetConfigCallback;
716 }
717 
718 
729 void USBD_LockEpStall(uint32_t u32EpBitmap)
730 {
731  g_u32EpStallLock = u32EpBitmap;
732 }
733 
734  /* end of group USBD_EXPORTED_FUNCTIONS */
736  /* end of group USBD_Driver */
738  /* end of group Standard_Driver */
740 
741 #ifdef __cplusplus
742 }
743 #endif
744 
745 /*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/
#define USBD_SET_DATA1(ep)
Set USB DATA1 PID for the specified endpoint ID.
Definition: usbd.h:418
void USBD_SwReset(void)
Reset software flags.
Definition: usbd.c:667
#define OTG_CTL_BUSREQ_Msk
Definition: otg_reg.h:541
void USBD_CtrlIn(void)
Repeat Control IN pipe.
Definition: usbd.c:553
void USBD_CtrlOut(void)
Repeat Control OUT pipe.
Definition: usbd.c:629
void(* VENDOR_REQ)(void)
Definition: usbd.h:660
#define USBD_GET_ADDR()
Get USB device address.
Definition: usbd.h:310
#define OTG_CTL_HNPREQEN_Msk
Definition: otg_reg.h:544
void(* SET_INTERFACE_REQ)(uint32_t u32AltInterface)
Definition: usbd.h:662
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:72
#define USBD_Minimum(a, b)
Compare two input numbers and return minimum one.
Definition: usbd.h:213
SET_INTERFACE_REQ g_usbd_pfnSetInterface
Definition: usbd.c:57
volatile uint8_t g_usbd_RemoteWakeupEn
Definition: usbd.c:33
#define USBD_EPSTS0_EPSTS1_Msk
Definition: usbd_reg.h:1048
#define USBD_GET_PAYLOAD_LEN(ep)
Get USB payload size (OUT data)
Definition: usbd.h:457
#define USBD_SET_EP_STALL(ep)
Set USB endpoint stall state.
Definition: usbd.h:509
#define M8(addr)
Get a 8-bit unsigned value from specified address.
Definition: M480.h:476
void USBD_LockEpStall(uint32_t u32EpBitmap)
EP stall lock function to avoid stall clear by USB SET FEATURE request.
Definition: usbd.c:729
#define USBD_SET_PAYLOAD_LEN(ep, size)
Set USB payload size (IN data)
Definition: usbd.h:445
uint32_t g_u32EpStallLock
Definition: usbd.c:59
#define USBD_INT_WAKEUP
Definition: usbd.h:147
uint8_t g_usbd_SetupPacket[8]
Definition: usbd.c:32
void(* SET_CONFIG_CB)(void)
Definition: usbd.h:663
NuMicro peripheral access layer header file.
#define USBD_CFG_DSQSYNC_Msk
Definition: usbd_reg.h:1111
SET_CONFIG_CB g_usbd_pfnSetConfigCallback
Definition: usbd.c:58
void USBD_StandardRequest(void)
Process standard request.
Definition: usbd.c:309
void USBD_SetConfigCallback(SET_CONFIG_CB pfnSetConfigCallback)
The callback function which called when get SET CONFIGURATION request.
Definition: usbd.c:713
#define USBD_SET_ADDR(addr)
Set USB device address.
Definition: usbd.h:298
#define OTG
Definition: M480.h:408
#define USBD_CLR_SE0()
Disable SE0.
Definition: usbd.h:286
uint8_t * gu8DevDesc
Definition: usbd.h:31
void USBD_GetSetupPacket(uint8_t *buf)
Get the received SETUP packet.
Definition: usbd.c:119
#define USBD
Definition: M480.h:407
uint32_t * gu32HidReportSize
Definition: usbd.h:36
void USBD_PrepareCtrlIn(uint8_t pu8Buf[], uint32_t u32Size)
Prepare the first Control IN pipe.
Definition: usbd.c:518
void USBD_Start(void)
This function makes USB host to recognize the device.
Definition: usbd.c:96
uint8_t ** gu8HidReportDesc
Definition: usbd.h:34
uint8_t * gu8BosDesc
Definition: usbd.h:35
uint8_t * gu8ConfigDesc
Definition: usbd.h:32
#define USBD_CLR_INT_FLAG(flag)
Clear USB interrupt flag.
Definition: usbd.h:352
#define USBD_GET_EP_BUF_ADDR(ep)
Get the offset of the specified USB endpoint buffer.
Definition: usbd.h:497
void USBD_SetVendorRequest(VENDOR_REQ pfnVendorReq)
USBD Set Vendor Request.
Definition: usbd.c:699
#define USBD_CFGP_SSTALL_Msk
Definition: usbd_reg.h:1120
void USBD_GetDescriptor(void)
Process GetDescriptor request.
Definition: usbd.c:184
const S_USBD_INFO_T * g_usbd_sInfo
Definition: usbd.c:53
VENDOR_REQ g_usbd_pfnVendorRequest
Definition: usbd.c:55
__STATIC_INLINE void USBD_SetStall(uint8_t epnum)
Set USB endpoint stall state.
Definition: usbd.h:571
#define EP1
Definition: usbd.h:55
#define USBD_MAX_EP
Definition: usbd.h:52
__STATIC_INLINE uint32_t USBD_GetStall(uint8_t epnum)
Get USB endpoint stall state.
Definition: usbd.h:635
#define USBD_INT_BUS
Definition: usbd.h:144
#define USBD_INT_FLDET
Definition: usbd.h:146
__STATIC_INLINE void USBD_MemCopy(uint8_t dest[], uint8_t src[], uint32_t size)
To support byte access between USB SRAM and system SRAM.
Definition: usbd.h:550
CLASS_REQ g_usbd_pfnClassRequest
Definition: usbd.c:56
#define USBD_SET_SE0()
Enable SE0. Force USB PHY transceiver to drive SE0.
Definition: usbd.h:274
#define NULL
NULL pointer.
Definition: M480.h:604
void(* CLASS_REQ)(void)
Definition: usbd.h:661
#define USBD_ENABLE_INT(intr)
Enable USB interrupt function.
Definition: usbd.h:325
uint8_t ** gu8StringDesc
Definition: usbd.h:33
void USBD_ProcessSetupPacket(void)
Process SETUP packet.
Definition: usbd.c:134
uint32_t * gu32ConfigHidDescIdx
Definition: usbd.h:37
#define USBD_BUF_BASE
Definition: usbd.h:51
#define USBD_INT_USB
Definition: usbd.h:145
#define EP0
Definition: usbd.h:54
void USBD_PrepareCtrlOut(uint8_t *pu8Buf, uint32_t u32Size)
Prepare the first Control OUT pipe.
Definition: usbd.c:611