Files
luban-lite-t3e-pro/packages/third-party/cherryusb/port/nuvoton/usb_dc_usbfs.c
刘可亮 9f7ba67007 v1.0.3
2024-01-27 08:47:24 +08:00

455 lines
15 KiB
C

#include <stdint.h>
#include "NuMicro.h"
#include "usbd_core.h"
#ifndef USBD_IRQHandler
#define USBD_IRQHandler USBD_IRQHandler
#endif
#ifndef USBD_EPNUM
#define USBD_EPNUM 8
#endif
#define USB_NUM_BIDIR_ENDPOINTS (USBD_EPNUM >> 1)
#define USBD_EP_GET_CONFIG(ep) (*((__IO uint32_t *)((uint32_t)&USBD->EP[0].CFG + (uint32_t)((ep) << 4))))
/* Define EP maximum packet size */
#define DEFAULT_EP_MAX_PKT_SIZE 64
#define EP0_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
#define EP1_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
#define EP2_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
#define EP3_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
#define EP4_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
#define EP5_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
#define EP6_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
#define EP7_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
#define EP8_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
#define EP9_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
#define EP10_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
#define EP11_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
#define SETUP_BUF_BASE 0
#define SETUP_BUF_LEN 8
#define EP0_BUF_BASE (SETUP_BUF_BASE + SETUP_BUF_LEN)
#define EP0_BUF_LEN EP0_MAX_PKT_SIZE
#define EP1_BUF_BASE (SETUP_BUF_BASE + SETUP_BUF_LEN)
#define EP1_BUF_LEN EP1_MAX_PKT_SIZE
#define EP2_BUF_BASE (EP1_BUF_BASE + EP1_BUF_LEN)
#define EP2_BUF_LEN EP2_MAX_PKT_SIZE
#define EP3_BUF_BASE (EP2_BUF_BASE + EP2_BUF_LEN)
#define EP3_BUF_LEN EP3_MAX_PKT_SIZE
#define EP4_BUF_BASE (EP3_BUF_BASE + EP3_BUF_LEN)
#define EP4_BUF_LEN EP4_MAX_PKT_SIZE
#define EP5_BUF_BASE (EP4_BUF_BASE + EP4_BUF_LEN)
#define EP5_BUF_LEN EP5_MAX_PKT_SIZE
#if USBD_EPNUM >= 8
#define EP6_BUF_BASE (EP5_BUF_BASE + EP5_BUF_LEN)
#define EP6_BUF_LEN EP6_MAX_PKT_SIZE
#define EP7_BUF_BASE (EP6_BUF_BASE + EP6_BUF_LEN)
#define EP7_BUF_LEN EP7_MAX_PKT_SIZE
#if USBD_EPNUM >= 10
#define EP8_BUF_BASE (EP7_BUF_BASE + EP7_BUF_LEN)
#define EP8_BUF_LEN EP8_MAX_PKT_SIZE
#define EP9_BUF_BASE (EP8_BUF_BASE + EP8_BUF_LEN)
#define EP9_BUF_LEN EP9_MAX_PKT_SIZE
#if USBD_EPNUM >= 12
#define EP10_BUF_BASE (EP9_BUF_BASE + EP9_BUF_LEN)
#define EP10_BUF_LEN EP10_MAX_PKT_SIZE
#define EP11_BUF_BASE (EP10_BUF_BASE + EP10_BUF_LEN)
#define EP11_BUF_LEN EP11_MAX_PKT_SIZE
#endif
#endif
#endif
#define USBD_EPNUM_FROM_IN_EPIDX(ep_idx) ((ep_idx) << 1)
#define USBD_EPNUM_FROM_OUT_EPIDX(ep_idx) (((ep_idx) << 1) + 1)
#define USBD_EPNUM_FROM_EPADDR(ep_addr) \
(USB_EP_DIR_IS_IN(ep_addr) ? USBD_EPNUM_FROM_IN_EPIDX(USB_EP_GET_IDX(ep_addr)) : USBD_EPNUM_FROM_OUT_EPIDX(USB_EP_GET_IDX(ep_addr)))
/* Endpoint state */
struct usb_dc_ep_state {
uint16_t ep_mps; /* Endpoint max packet size */
uint8_t ep_type; /* Endpoint type */
uint8_t ep_stalled; /* Endpoint stall flag */
uint8_t ep_enable; /* Endpoint enable */
uint8_t *xfer_buf;
uint32_t xfer_len;
uint32_t actual_xfer_len;
uint32_t mps_xfer_len;
};
/* Driver state */
struct usb_dc_config_priv {
volatile uint8_t dev_addr;
struct usb_dc_ep_state in_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< IN endpoint parameters*/
struct usb_dc_ep_state out_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< OUT endpoint parameters */
} g_nuvoton_udc;
static uint8_t usdb_set_address_flag = 0;
static uint8_t usbd_out_toggle[USB_NUM_BIDIR_ENDPOINTS] = { 0 };
__WEAK void usb_dc_low_level_init(void)
{
}
__WEAK void usb_dc_low_level_deinit(void)
{
}
int usb_dc_init(void)
{
memset(&g_nuvoton_udc, 0, sizeof(g_nuvoton_udc));
usb_dc_low_level_init();
/*****************************************************/
/* Initial USB engine */
USBD->ATTR = 0x6D0ul;
/* Force SE0 */
USBD_SET_SE0();
/*****************************************************/
/* Init setup packet buffer */
/* Buffer for setup packet -> [0 ~ 0x7] */
USBD->STBUFSEG = SETUP_BUF_BASE;
USBD_SET_EP_BUF_ADDR(EP0, EP0_BUF_BASE);
USBD_SET_EP_BUF_ADDR(EP1, EP1_BUF_BASE);
USBD_SET_EP_BUF_ADDR(EP2, EP2_BUF_BASE);
USBD_SET_EP_BUF_ADDR(EP3, EP3_BUF_BASE);
USBD_SET_EP_BUF_ADDR(EP4, EP4_BUF_BASE);
USBD_SET_EP_BUF_ADDR(EP5, EP5_BUF_BASE);
#if USBD_EPNUM >= 8
USBD_SET_EP_BUF_ADDR(EP6, EP6_BUF_BASE);
USBD_SET_EP_BUF_ADDR(EP7, EP7_BUF_BASE);
#if USBD_EPNUM >= 10
USBD_SET_EP_BUF_ADDR(EP8, EP8_BUF_BASE);
USBD_SET_EP_BUF_ADDR(EP9, EP9_BUF_BASE);
USBD_SET_EP_BUF_ADDR(EP10, EP10_BUF_BASE);
#if USBD_EPNUM >= 12
USBD_SET_EP_BUF_ADDR(EP11, EP11_BUF_BASE);
#endif
#endif
#endif
/*****************************************************/
/* USB start */
/* Disable software-disconnect function */
USBD_CLR_SE0();
USBD->ATTR = 0x7D0ul;
/* Clear USB-related interrupts before enable interrupt */
USBD_CLR_INT_FLAG(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP);
/* Enable USB-related interrupts. */
USBD_ENABLE_INT(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP);
/*****************************************************/
return 0;
}
int usb_dc_deinit(void)
{
USBD->ATTR = 0x00000040;
/* Force SE0 */
USBD_SET_SE0();
return 0;
}
int usbd_set_address(const uint8_t addr)
{
uint8_t usbd_addr = USBD_GET_ADDR();
if ((usbd_addr == 0) && (usbd_addr != addr)) {
g_nuvoton_udc.dev_addr = addr;
usdb_set_address_flag = 1;
}
return 0;
}
uint8_t usbd_get_port_speed(const uint8_t port)
{
return USB_SPEED_FULL;
}
int usbd_ep_open(const struct usb_endpoint_descriptor *ep)
{
uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
if (USB_EP_DIR_IS_IN(ep->bEndpointAddress)) {
uint8_t epnum = USBD_EPNUM_FROM_IN_EPIDX(ep_idx);
g_nuvoton_udc.in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
g_nuvoton_udc.in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
g_nuvoton_udc.in_ep[ep_idx].ep_enable = true;
if (ep_idx == 0) {
/* EP0 ==> control IN endpoint, address 0 */
USBD_CONFIG_EP(EP0, USBD_CFG_CSTALL | USBD_CFG_EPMODE_IN | 0);
} else {
USBD_CONFIG_EP(epnum, USBD_CFG_EPMODE_IN | ep_idx);
USBD_STOP_TRANSACTION(epnum);
}
} else {
uint8_t epnum = USBD_EPNUM_FROM_OUT_EPIDX(ep_idx);
g_nuvoton_udc.out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
g_nuvoton_udc.out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
g_nuvoton_udc.out_ep[ep_idx].ep_enable = true;
if (ep_idx == 0) {
/* EP1 ==> control OUT endpoint, address 0 */
USBD_CONFIG_EP(EP1, USBD_CFG_CSTALL | USBD_CFG_EPMODE_OUT | 0);
} else {
USBD_CONFIG_EP(epnum, USBD_CFG_EPMODE_OUT | ep_idx);
USBD_STOP_TRANSACTION(epnum);
}
}
return 0;
}
int usbd_ep_close(const uint8_t ep)
{
USBD->EP[USBD_EPNUM_FROM_EPADDR(ep)].CFG &= ~USBD_CFG_STATE_Msk; // disable endpoint
return 0;
}
int usbd_ep_set_stall(const uint8_t ep)
{
USBD_SET_EP_STALL(USBD_EPNUM_FROM_EPADDR(ep));
return 0;
}
int usbd_ep_clear_stall(const uint8_t ep)
{
USBD_CLR_EP_STALL(USBD_EPNUM_FROM_EPADDR(ep));
return 0;
}
int usbd_ep_is_stalled(const uint8_t ep, uint8_t *stalled)
{
*stalled = USBD_GET_EP_STALL(USBD_EPNUM_FROM_EPADDR(ep)) > 0 ? 1 : 0;
return 0;
}
int usbd_ep_start_write(const uint8_t ep, const uint8_t *data, uint32_t data_len)
{
uint8_t ep_idx = USB_EP_GET_IDX(ep);
if (!data && data_len) {
return -1;
}
if (!g_nuvoton_udc.in_ep[ep_idx].ep_enable) {
return -2;
}
uint8_t epnum = USBD_EPNUM_FROM_IN_EPIDX(ep);
g_nuvoton_udc.in_ep[ep_idx].xfer_buf = (uint8_t *)data;
g_nuvoton_udc.in_ep[ep_idx].xfer_len = data_len;
g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len = 0;
if (data_len > g_nuvoton_udc.in_ep[ep_idx].ep_mps) {
data_len = g_nuvoton_udc.in_ep[ep_idx].ep_mps;
}
if (epnum == 0) {
USBD_SET_DATA1(epnum);
}
USBD_MemCopy((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(epnum)), (uint8_t *)data, data_len);
USBD_SET_PAYLOAD_LEN(epnum, data_len);
return 0;
}
int usbd_ep_start_read(const uint8_t ep, uint8_t *data, uint32_t data_len)
{
uint8_t ep_idx = USB_EP_GET_IDX(ep);
if (!data && data_len) {
return -1;
}
if (!g_nuvoton_udc.out_ep[ep_idx].ep_enable) {
return -2;
}
uint8_t epnum = USBD_EPNUM_FROM_OUT_EPIDX(ep);
g_nuvoton_udc.out_ep[ep_idx].xfer_buf = (uint8_t *)data;
g_nuvoton_udc.out_ep[ep_idx].xfer_len = data_len;
g_nuvoton_udc.out_ep[ep_idx].actual_xfer_len = 0;
if (g_nuvoton_udc.out_ep[ep_idx].xfer_len < g_nuvoton_udc.out_ep[ep_idx].ep_mps) {
g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].xfer_len;
} else {
g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].ep_mps;
}
USBD_SET_PAYLOAD_LEN(epnum, g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len);
return 0;
}
void USBD_IRQHandler(void)
{
uint32_t int_flag = USBD_GET_INT_FLAG();
uint32_t bus_state = USBD_GET_BUS_STATE();
if (int_flag & USBD_INTSTS_FLDET) {
// Floating detect
USBD_CLR_INT_FLAG(USBD_INTSTS_FLDET);
if (USBD_IS_ATTACHED()) {
/* USB Plug In */
USBD_ENABLE_USB();
usbd_event_connect_handler();
} else {
/* USB Un-plug */
USBD_DISABLE_USB();
usbd_event_disconnect_handler();
}
}
//------------------------------------------------------------------
if (int_flag & USBD_INTSTS_BUS) {
/* Clear event flag */
USBD_CLR_INT_FLAG(USBD_INTSTS_BUS);
if (bus_state & USBD_STATE_USBRST) {
/* Bus reset */
USBD_ENABLE_USB();
memset((usbd_out_toggle + 1), 0, (USB_NUM_BIDIR_ENDPOINTS - 1));
for (uint8_t i = 0; i < USBD_MAX_EP; i++) {
USBD->EP[i].CFG = 0; // default value
}
USBD_SET_ADDR(0ul);
g_nuvoton_udc.dev_addr = 0;
usbd_event_reset_handler();
}
if (bus_state & USBD_STATE_SUSPEND) {
/* Enable USB but disable PHY */
USBD_DISABLE_PHY();
usbd_event_suspend_handler();
}
if (bus_state & USBD_STATE_RESUME) {
/* Enable USB and enable PHY */
USBD_ENABLE_USB();
usbd_event_resume_handler();
}
}
//------------------------------------------------------------------
if (int_flag & USBD_INTSTS_WAKEUP) {
/* Clear event flag */
USBD_CLR_INT_FLAG(USBD_INTSTS_WAKEUP);
}
if (int_flag & USBD_INTSTS_USB) {
// USB event
if (int_flag & USBD_INTSTS_SETUP) {
// Setup packet
/* Clear event flag */
USBD_CLR_INT_FLAG(USBD_INTSTS_SETUP);
/* Clear the data IN/OUT ready flag of control end-points */
USBD_STOP_TRANSACTION(EP0);
USBD_STOP_TRANSACTION(EP1);
usbd_out_toggle[0] = 0;
usbd_event_ep0_setup_complete_handler((uint8_t *)(USBD_BUF_BASE));
}
if (int_flag & USBD_INTSTS_EP0) {
/* In ACK for Set address */
if (usdb_set_address_flag == 1) {
USBD_SET_ADDR(g_nuvoton_udc.dev_addr);
usdb_set_address_flag = 0;
}
}
// if (int_flag & USBD_INTSTS_EP1)
// {
// }
for (uint8_t epnum = 0; epnum < USBD_EPNUM; epnum++) {
if (int_flag & (USBD_INTSTS_EP0 << epnum)) {
USBD_CLR_INT_FLAG((USBD_INTSTS_EP0 << epnum));
uint8_t ep_cfg = USBD_EP_GET_CONFIG(epnum);
uint8_t ep_state = 0;
#if USBD_EPNUM >= 10
if (epnum > 7) {
ep_state = (USBD->EPSTS1 >> ((epnum - 8) * 4)) & 0x0f;
} else
#endif
{
ep_state = (USBD->EPSTS0 >> (epnum * 4)) & 0x0f;
}
uint8_t ep_cfg_state = (ep_cfg & USBD_CFG_STATE_Msk) >> USBD_CFG_STATE_Pos;
if (ep_cfg_state == 0x01) {
// OUT
uint8_t ep_idx = ep_cfg & USBD_CFG_EPNUM_Msk;
if (ep_state == usbd_out_toggle[ep_idx]) {
USBD_SET_PAYLOAD_LEN(epnum, g_nuvoton_udc.out_ep[ep_idx].ep_mps);
} else {
uint32_t recv_count = USBD_GET_PAYLOAD_LEN(epnum);
USBD_MemCopy((uint8_t *)g_nuvoton_udc.out_ep[ep_idx].xfer_buf,
(uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(epnum)), recv_count);
g_nuvoton_udc.out_ep[ep_idx].xfer_buf += recv_count;
g_nuvoton_udc.out_ep[ep_idx].xfer_len -= recv_count;
g_nuvoton_udc.out_ep[ep_idx].actual_xfer_len += recv_count;
usbd_out_toggle[ep_idx] = ep_state;
if ((recv_count < g_nuvoton_udc.out_ep[ep_idx].ep_mps) ||
(g_nuvoton_udc.out_ep[ep_idx].xfer_len == 0)) {
usbd_event_ep_out_complete_handler(ep_idx, g_nuvoton_udc.out_ep[ep_idx].actual_xfer_len);
} else {
if (g_nuvoton_udc.out_ep[ep_idx].xfer_len < g_nuvoton_udc.out_ep[ep_idx].ep_mps) {
g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].xfer_len;
} else {
g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].ep_mps;
}
USBD_SET_PAYLOAD_LEN(epnum, g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len);
}
}
} else if (ep_cfg_state == 0x02) {
uint8_t ep_idx = ep_cfg & USBD_CFG_EPNUM_Msk;
// In Ack
if (g_nuvoton_udc.in_ep[ep_idx].xfer_len > g_nuvoton_udc.in_ep[ep_idx].ep_mps) {
g_nuvoton_udc.in_ep[ep_idx].xfer_buf += g_nuvoton_udc.in_ep[ep_idx].ep_mps;
g_nuvoton_udc.in_ep[ep_idx].xfer_len -= g_nuvoton_udc.in_ep[ep_idx].ep_mps;
g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len += g_nuvoton_udc.in_ep[ep_idx].ep_mps;
uint16_t min_len = MIN(g_nuvoton_udc.in_ep[ep_idx].xfer_len, g_nuvoton_udc.in_ep[ep_idx].ep_mps);
uint8_t *usbd_ep_buf_addr = (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(epnum));
USBD_MemCopy(usbd_ep_buf_addr, g_nuvoton_udc.in_ep[ep_idx].xfer_buf, min_len);
USBD_SET_PAYLOAD_LEN(epnum, min_len);
} else {
g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len += g_nuvoton_udc.in_ep[ep_idx].xfer_len;
g_nuvoton_udc.in_ep[ep_idx].xfer_len = 0;
usbd_event_ep_in_complete_handler(ep_idx | 0x80, g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len);
}
}
}
}
}
}