#include "usbd_core.h" #include "usb_nuvoton_reg.h" #ifndef USBD_IRQHandler #define USBD_IRQHandler USBD_IRQHandler #endif #ifndef USB_BASE #define USB_BASE (0x40019000UL) #endif #ifndef USB_NUM_BIDIR_ENDPOINTS #define USB_NUM_BIDIR_ENDPOINTS 13 #endif #define USBD ((USBD_T *)USB_BASE) #define USBD_ENABLE_USB() ((uint32_t)(USBD->PHYCTL |= (USBD_PHYCTL_PHYEN_Msk | USBD_PHYCTL_DPPUEN_Msk))) /*!PHYCTL &= ~USBD_PHYCTL_DPPUEN_Msk)) /*!PHYCTL |= USBD_PHYCTL_PHYEN_Msk)) /*!PHYCTL &= ~USBD_PHYCTL_PHYEN_Msk)) /*!PHYCTL &= ~USBD_PHYCTL_DPPUEN_Msk)) /*!PHYCTL |= USBD_PHYCTL_DPPUEN_Msk)) /*!FADDR = (addr)) /*!FADDR)) /*!GINTEN = (intr)) /*!BUSINTEN = (intr)) /*!BUSINTSTS) /*!BUSINTSTS = flag) /*!CEPINTEN = (intr)) /*!CEPINTSTS = flag) /*!CEPCTL = flag) /*!CEPTXCNT = size) /*!EP[ep].EPMPS = (size)) /*!EP[ep].EPINTEN = (intr)) /*!EP[ep].EPINTSTS) /*!EP[ep].EPINTSTS = (flag)) /*!DMACNT = len) /*!DMAADDR = addr) /*!DMACTL = (USBD->DMACTL & ~USBD_DMACTL_EPNUM_Msk) | USBD_DMACTL_DMARD_Msk | epnum | 0x100) /*!DMACTL = (USBD->DMACTL & ~(USBD_DMACTL_EPNUM_Msk | USBD_DMACTL_DMARD_Msk | 0x100)) | epnum) /*!DMACTL |= USBD_DMACTL_DMAEN_Msk) /*!PHYCTL & USBD_PHYCTL_VBUSDET_Msk)) /*!cep.CEPDAT_BYTE = *buf8; buf8++; } } else { for (i = 0; i < len; i++) { USBD->EP[ep_idx - 1].ep.EPDAT_BYTE = *buf8; buf8++; } } } else { count32 = len >> 2; count8 = len & 0x03; buf32 = (uint32_t *)buffer; if (ep_idx == 0) { while (count32--) { USBD->cep.CEPDAT = *buf32; buf32++; } buf8 = (uint8_t *)buf32; while (count8--) { USBD->cep.CEPDAT_BYTE = *buf8; buf8++; } } else { while (count32--) { USBD->EP[ep_idx - 1].ep.EPDAT = *buf32; buf32++; } buf8 = (uint8_t *)buf32; while (count8--) { USBD->EP[ep_idx - 1].ep.EPDAT_BYTE = *buf8; buf8++; } } } } static void usb_fifo_read(uint8_t ep_idx, uint8_t *buffer, uint16_t len) { uint32_t *buf32; uint8_t *buf8; uint32_t count32; uint32_t count8; int i; if ((uint32_t)buffer & 0x03) { buf8 = buffer; if (ep_idx == 0) { for (i = 0; i < len; i++) { *buf8 = USBD->cep.CEPDAT_BYTE; buf8++; } } else { for (i = 0; i < len; i++) { *buf8 = USBD->EP[ep_idx - 1].ep.EPDAT_BYTE; buf8++; } } } else { count32 = len >> 2; count8 = len & 0x03; buf32 = (uint32_t *)buffer; if (ep_idx == 0) { while (count32--) { *buf32 = USBD->cep.CEPDAT; buf32++; } buf8 = (uint8_t *)buf32; while (count8--) { *buf8 = USBD->cep.CEPDAT_BYTE; buf8++; } } else { while (count32--) { *buf32 = USBD->EP[ep_idx - 1].ep.EPDAT; buf32++; } buf8 = (uint8_t *)buf32; while (count8--) { *buf8 = USBD->EP[ep_idx - 1].ep.EPDAT_BYTE; buf8++; } } } } __WEAK void usb_dc_low_level_init(void) { } __WEAK void usb_dc_low_level_deinit(void) { } int usb_dc_init(void) { memset(&usb_dc_cfg, 0, sizeof(struct usb_dc_config_priv)); usb_dc_low_level_init(); /* Enable PHY */ USBD_ENABLE_PHY(); /* wait PHY clock ready */ while (1) { USBD->EP[0].EPMPS = 0x20; if (USBD->EP[0].EPMPS == 0x20) break; } #ifdef CONFIG_USB_HS USBD->OPER |= USBD_OPER_HISPDEN_Msk; /* high-speed */ #else USBD->OPER &= ~USBD_OPER_HISPDEN_Msk; /* full-speed */ #endif /* Reset Address to 0 */ USBD_SET_ADDR(0); USBD->CEPINTEN = USBD_CEPINTEN_SETUPPKIEN_Msk | USBD_CEPINTEN_TXPKIEN_Msk | USBD_CEPINTEN_RXPKIEN_Msk | USBD_CEPINTEN_STSDONEIEN_Msk; /* Enable BUS interrupt */ USBD->BUSINTEN = USBD_BUSINTEN_RSTIEN_Msk | USBD_BUSINTEN_VBUSDETIEN_Msk; /* Enable USB BUS, CEP and EPA global interrupt */ USBD->GINTEN = USBD_GINTEN_USBIE_Msk | USBD_GINTEN_CEPIE_Msk; return 0; } int usb_dc_deinit(void) { return 0; } int usbd_set_address(const uint8_t addr) { if (addr == 0x00) { } usb_dc_cfg.dev_addr = addr; return 0; } int usbd_ep_open(const struct usbd_endpoint_cfg *ep_cfg) { uint8_t ep_idx = USB_EP_GET_IDX(ep_cfg->ep_addr); uint8_t ep_type; uint8_t ep_dir; uint32_t intr; if (USB_EP_DIR_IS_OUT(ep_cfg->ep_addr)) { ep_dir = USB_EP_CFG_DIR_OUT; intr = USBD_EPINTEN_RXPKIEN_Msk; usb_dc_cfg.out_ep[ep_idx].ep_mps = ep_cfg->ep_mps; usb_dc_cfg.out_ep[ep_idx].ep_type = ep_cfg->ep_type; } else { ep_dir = USB_EP_CFG_DIR_IN; intr = USBD_EPINTEN_TXPKIEN_Msk; usb_dc_cfg.in_ep[ep_idx].ep_mps = ep_cfg->ep_mps; usb_dc_cfg.in_ep[ep_idx].ep_type = ep_cfg->ep_type; } if (ep_idx == 0) { /* Control endpoint */ USBD->CEPBUFSTART = usb_dc_cfg.bufaddr; USBD->CEPBUFEND = usb_dc_cfg.bufaddr + 64 - 1; usb_dc_cfg.bufaddr += 64; return 0; } switch (ep_cfg->ep_type) { case 0x01: ep_type = USB_EP_CFG_TYPE_ISO; USBD->EP[ep_idx - 1].EPRSPCTL = (USB_EP_RSPCTL_FLUSH | USB_EP_RSPCTL_MODE_FLY); break; case 0x02: ep_type = USB_EP_CFG_TYPE_BULK; USBD->EP[ep_idx - 1].EPRSPCTL = (USB_EP_RSPCTL_FLUSH | USB_EP_RSPCTL_MODE_AUTO); break; case 0x03: ep_type = USB_EP_CFG_TYPE_INT; USBD->EP[ep_idx - 1].EPRSPCTL = (USB_EP_RSPCTL_FLUSH | USB_EP_RSPCTL_MODE_MANUAL); break; } USBD->EP[ep_idx - 1].EPBUFSTART = usb_dc_cfg.bufaddr; USBD->EP[ep_idx - 1].EPBUFEND = usb_dc_cfg.bufaddr + ep_cfg->ep_mps - 1; USBD->EP[ep_idx - 1].EPMPS = ep_cfg->ep_mps; USBD->EP[ep_idx - 1].EPCFG = (ep_type | ep_dir | USB_EP_CFG_VALID | (ep_idx << 4)); USBD->EP[ep_idx - 1].EPINTEN = intr; USBD->GINTEN |= (1 << (USBD_GINTEN_CEPIE_Pos + ep_idx)); usb_dc_cfg.bufaddr += ep_cfg->ep_mps; return 0; } int usbd_ep_close(const uint8_t ep) { return 0; } int usbd_ep_set_stall(const uint8_t ep) { uint8_t ep_idx = USB_EP_GET_IDX(ep); if (ep_idx == 0x00) { USBD_SET_CEP_STATE(USB_CEPCTL_STALL); } else { USBD->EP[ep_idx - 1].EPRSPCTL = (USBD->EP[ep_idx - 1].EPRSPCTL & 0xf7) | USB_EP_RSPCTL_HALT; } return 0; } int usbd_ep_clear_stall(const uint8_t ep) { uint8_t ep_idx = USB_EP_GET_IDX(ep); if (ep_idx == 0x00) { return 0; } USBD->EP[ep_idx - 1].EPRSPCTL = USB_EP_RSPCTL_TOGGLE; return 0; } int usbd_ep_is_stalled(const uint8_t ep, uint8_t *stalled) { return 0; } int usbd_ep_write(const uint8_t ep, const uint8_t *data, uint32_t data_len, uint32_t *ret_bytes) { uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!data && data_len) { return -1; } if (!data_len) { if (ep_idx == 0x00) { USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR); } else { USBD->EP[ep_idx - 1].EPRSPCTL = USB_EP_RSPCTL_ZEROLEN; } return 0; } if (data_len > usb_dc_cfg.in_ep[ep_idx].ep_mps) { data_len = usb_dc_cfg.in_ep[ep_idx].ep_mps; } if (ep_idx == 0x00) { usb_fifo_write(0, (uint8_t *)data, data_len); USBD->CEPTXCNT = data_len; USBD->CEPCTL = USB_CEPCTL_NAKCLR; } else { while (USBD->EP[ep_idx - 1].EPDATCNT != 0) { } usb_fifo_write(ep_idx, (uint8_t *)data, data_len); USBD->EP[ep_idx - 1].EPTXCNT = data_len; USBD->EP[ep_idx - 1].EPRSPCTL = USB_EP_RSPCTL_SHORTTXEN; } if (ret_bytes) { *ret_bytes = data_len; } return 0; } int usbd_ep_read(const uint8_t ep, uint8_t *data, uint32_t max_data_len, uint32_t *read_bytes) { uint8_t ep_idx = USB_EP_GET_IDX(ep); uint32_t read_count; if (!data && max_data_len) { return -1; } if (!max_data_len) { return 0; } if (ep_idx == 0x00) { if (max_data_len == 0x08 && !read_bytes) { *((uint16_t *)(data + 0)) = (uint16_t)(USBD->SETUP1_0 & 0xFFFFUL); *((uint16_t *)(data + 2)) = (uint16_t)(USBD->SETUP3_2 & 0xFFFFUL); *((uint16_t *)(data + 4)) = (uint16_t)(USBD->SETUP5_4 & 0xFFFFUL); *((uint16_t *)(data + 6)) = (uint16_t)(USBD->SETUP7_6 & 0xFFFFUL); } else { read_count = USBD->CEPRXCNT & 0xFFFFUL; read_count = MIN(read_count, max_data_len); usb_fifo_read(0, data, read_count); } } else { read_count = USBD->EP[ep_idx - 1].EPDATCNT & 0xFFFFUL; read_count = MIN(read_count, max_data_len); usb_fifo_read(ep_idx, data, read_count); } if (read_bytes) { *read_bytes = read_count; } return 0; } void USBD_IRQHandler(void) { volatile uint32_t IrqStL, IrqSt; IrqStL = USBD->GINTSTS & USBD->GINTEN; /* get interrupt status */ if (!IrqStL) return; /* USB interrupt */ if (IrqStL & USBD_GINTSTS_USBIF_Msk) { IrqSt = USBD->BUSINTSTS & USBD->BUSINTEN; if (IrqSt & USBD_BUSINTSTS_SOFIF_Msk) { USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_SOFIF_Msk); } if (IrqSt & USBD_BUSINTSTS_RSTIF_Msk) { USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_RSTIF_Msk); USBD->DMACNT = 0; USBD->DMACTL = 0x80; USBD->DMACTL = 0x00; for (uint8_t i = 1; i < USB_NUM_BIDIR_ENDPOINTS; i++) { USBD->EP[i - 1].EPRSPCTL = USBD_EPRSPCTL_FLUSH_Msk; } USBD_SET_ADDR(0); USBD_CLR_CEP_INT_FLAG(0x1ffc); usb_dc_cfg.bufaddr = 0; usbd_event_notify_handler(USBD_EVENT_RESET, NULL); } if (IrqSt & USBD_BUSINTSTS_RESUMEIF_Msk) { USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_RESUMEIF_Msk); } if (IrqSt & USBD_BUSINTSTS_SUSPENDIF_Msk) { USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_SUSPENDIF_Msk); } if (IrqSt & USBD_BUSINTSTS_HISPDIF_Msk) { USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_HISPDIF_Msk); } if (IrqSt & USBD_BUSINTSTS_DMADONEIF_Msk) { USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_DMADONEIF_Msk); if (USBD->DMACTL & USBD_DMACTL_DMARD_Msk) { } } if (IrqSt & USBD_BUSINTSTS_PHYCLKVLDIF_Msk) USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_PHYCLKVLDIF_Msk); if (IrqSt & USBD_BUSINTSTS_VBUSDETIF_Msk) { if (USBD_IS_ATTACHED()) { /* USB Plug In */ USBD_ENABLE_USB(); } else { /* USB Un-plug */ USBD_DISABLE_USB(); } USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_VBUSDETIF_Msk); } } if (IrqStL & USBD_GINTSTS_CEPIF_Msk) { IrqSt = USBD->CEPINTSTS & USBD->CEPINTEN; if (IrqSt & USBD_CEPINTSTS_SETUPTKIF_Msk) { USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_SETUPTKIF_Msk); return; } if (IrqSt & USBD_CEPINTSTS_OUTTKIF_Msk) { USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_OUTTKIF_Msk); return; } if (IrqSt & USBD_CEPINTSTS_INTKIF_Msk) { USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_INTKIF_Msk); return; } if (IrqSt & USBD_CEPINTSTS_PINGIF_Msk) { USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_PINGIF_Msk); return; } if (IrqSt & USBD_CEPINTSTS_SETUPPKIF_Msk) { USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_SETUPPKIF_Msk); usbd_event_notify_handler(USBD_EVENT_SETUP_NOTIFY, NULL); return; } if (IrqSt & USBD_CEPINTSTS_TXPKIF_Msk) { USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_TXPKIF_Msk); usbd_event_notify_handler(USBD_EVENT_EP0_IN_NOTIFY, NULL); return; } if (IrqSt & USBD_CEPINTSTS_RXPKIF_Msk) { USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_RXPKIF_Msk); usbd_event_notify_handler(USBD_EVENT_EP0_OUT_NOTIFY, NULL); return; } if (IrqSt & USBD_CEPINTSTS_NAKIF_Msk) { USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_NAKIF_Msk); return; } if (IrqSt & USBD_CEPINTSTS_STALLIF_Msk) { USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STALLIF_Msk); return; } if (IrqSt & USBD_CEPINTSTS_ERRIF_Msk) { USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_ERRIF_Msk); return; } if (IrqSt & USBD_CEPINTSTS_STSDONEIF_Msk) { USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STSDONEIF_Msk); if (usb_dc_cfg.dev_addr > 0) { USBD_SET_ADDR(usb_dc_cfg.dev_addr); usb_dc_cfg.dev_addr = 0; } return; } if (IrqSt & USBD_CEPINTSTS_BUFFULLIF_Msk) { USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_BUFFULLIF_Msk); return; } if (IrqSt & USBD_CEPINTSTS_BUFEMPTYIF_Msk) { USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_BUFEMPTYIF_Msk); return; } } for (uint8_t ep_idx = 1; ep_idx < USB_NUM_BIDIR_ENDPOINTS; ep_idx++) { if (IrqStL & (0x1UL << (USBD_GINTSTS_CEPIF_Pos + ep_idx))) { IrqSt = USBD->EP[ep_idx - 1].EPINTSTS & USBD->EP[ep_idx - 1].EPINTEN; USBD_CLR_EP_INT_FLAG(ep_idx - 1, IrqSt); if (usb_dc_cfg.in_ep[ep_idx].ep_mps) { usbd_event_notify_handler(USBD_EVENT_EP_IN_NOTIFY, (void *)(0x80 | ep_idx)); } else if (usb_dc_cfg.out_ep[ep_idx].ep_mps) { usbd_event_notify_handler(USBD_EVENT_EP_OUT_NOTIFY, (void *)(ep_idx & 0x7f)); } } } }