578 lines
16 KiB
C
578 lines
16 KiB
C
|
/**************************************************************************//**
|
||
|
*
|
||
|
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
|
||
|
*
|
||
|
* SPDX-License-Identifier: Apache-2.0
|
||
|
*
|
||
|
* Change Logs:
|
||
|
* Date Author Notes
|
||
|
* 2022-3-15 Wayne First version
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
#include <rtconfig.h>
|
||
|
|
||
|
#if defined(BSP_USING_USBD)
|
||
|
#include <rtthread.h>
|
||
|
#include <rtdevice.h>
|
||
|
#include "NuMicro.h"
|
||
|
#include <nu_bitutil.h>
|
||
|
|
||
|
#define LOG_TAG "drv.usbd"
|
||
|
#define DBG_ENABLE
|
||
|
#define DBG_SECTION_NAME "drv.usbd"
|
||
|
#define DBG_LEVEL DBG_ERROR
|
||
|
#define DBG_COLOR
|
||
|
#include <rtdbg.h>
|
||
|
|
||
|
/* Private define ---------------------------------------------------------------*/
|
||
|
/* Define EP maximum packet size */
|
||
|
#define EP0_MAX_PKT_SIZE 64
|
||
|
#define EP1_MAX_PKT_SIZE EP0_MAX_PKT_SIZE /* EP0 and EP1 are assigned the same size for control endpoint */
|
||
|
#define EP2_MAX_PKT_SIZE 64
|
||
|
#define EP3_MAX_PKT_SIZE 64
|
||
|
#define EP4_MAX_PKT_SIZE 32
|
||
|
#define EP5_MAX_PKT_SIZE 32
|
||
|
#define EP6_MAX_PKT_SIZE 64
|
||
|
#define EP7_MAX_PKT_SIZE 64
|
||
|
#define EP8_MAX_PKT_SIZE 32
|
||
|
#define EP9_MAX_PKT_SIZE 32
|
||
|
#define EP10_MAX_PKT_SIZE 64
|
||
|
#define EP11_MAX_PKT_SIZE 64
|
||
|
#define EP12_MAX_PKT_SIZE 32
|
||
|
#define EP13_MAX_PKT_SIZE 32
|
||
|
#define EP14_MAX_PKT_SIZE 64
|
||
|
#define EP15_MAX_PKT_SIZE 64
|
||
|
#define EP16_MAX_PKT_SIZE 32
|
||
|
#define EP17_MAX_PKT_SIZE 32
|
||
|
#define EP18_MAX_PKT_SIZE 64
|
||
|
#define EP19_MAX_PKT_SIZE 64
|
||
|
#define EP20_MAX_PKT_SIZE 32
|
||
|
#define EP21_MAX_PKT_SIZE 32
|
||
|
#define EP22_MAX_PKT_SIZE 64
|
||
|
#define EP23_MAX_PKT_SIZE 64
|
||
|
#define EP24_MAX_PKT_SIZE 32
|
||
|
|
||
|
#define SETUP_BUF_BASE 0
|
||
|
#define SETUP_BUF_LEN 8
|
||
|
|
||
|
#define EPADR_SW2HW(address) ((((address & USB_EPNO_MASK) * 2) + (!(address & USB_DIR_IN))))
|
||
|
#define EPADR_HW2SW(address) ((address & USB_EPNO_MASK) / 2)
|
||
|
|
||
|
/* Private typedef --------------------------------------------------------------*/
|
||
|
struct nu_usbd
|
||
|
{
|
||
|
USBD_T *Instance; /* REG base */
|
||
|
uint8_t address_tmp; /* Keep assigned address for flow control */
|
||
|
};
|
||
|
typedef struct nu_usbd *nu_usbd_t;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
|
||
|
uint32_t u32BufferBase;
|
||
|
uint32_t u32BufferLength;
|
||
|
|
||
|
uint32_t u32;
|
||
|
|
||
|
} S_EP_CXT;
|
||
|
|
||
|
/* Private variables ------------------------------------------------------------*/
|
||
|
static struct nu_usbd nu_usbd_obj =
|
||
|
{
|
||
|
.Instance = USBD,
|
||
|
.address_tmp = 0,
|
||
|
};
|
||
|
|
||
|
static struct udcd _rt_obj_udc;
|
||
|
|
||
|
static const uint32_t s_au32MaxPktSize[USBD_MAX_EP] =
|
||
|
{
|
||
|
EP0_MAX_PKT_SIZE, //EP0
|
||
|
EP1_MAX_PKT_SIZE, //EP1
|
||
|
EP2_MAX_PKT_SIZE, //EP2
|
||
|
EP3_MAX_PKT_SIZE, //EP3
|
||
|
EP4_MAX_PKT_SIZE, //EP4
|
||
|
EP5_MAX_PKT_SIZE, //EP5
|
||
|
EP6_MAX_PKT_SIZE, //EP6
|
||
|
EP7_MAX_PKT_SIZE, //EP7
|
||
|
EP8_MAX_PKT_SIZE, //EP8
|
||
|
EP9_MAX_PKT_SIZE, //EP9
|
||
|
EP10_MAX_PKT_SIZE, //EP10
|
||
|
EP11_MAX_PKT_SIZE, //EP11
|
||
|
EP12_MAX_PKT_SIZE, //EP12
|
||
|
EP13_MAX_PKT_SIZE, //EP13
|
||
|
EP14_MAX_PKT_SIZE, //EP14
|
||
|
EP15_MAX_PKT_SIZE, //EP15
|
||
|
EP16_MAX_PKT_SIZE, //EP16
|
||
|
EP17_MAX_PKT_SIZE, //EP17
|
||
|
EP18_MAX_PKT_SIZE, //EP18
|
||
|
EP19_MAX_PKT_SIZE, //EP19
|
||
|
EP20_MAX_PKT_SIZE, //EP20
|
||
|
EP21_MAX_PKT_SIZE, //EP21
|
||
|
EP22_MAX_PKT_SIZE, //EP22
|
||
|
EP23_MAX_PKT_SIZE, //EP23
|
||
|
EP24_MAX_PKT_SIZE //EP24
|
||
|
};
|
||
|
|
||
|
static struct ep_id _ep_pool[] =
|
||
|
{
|
||
|
{EPADR_HW2SW(EP0), USB_EP_ATTR_CONTROL, USB_DIR_INOUT, EP0_MAX_PKT_SIZE, ID_ASSIGNED },
|
||
|
{EPADR_HW2SW(EP2), USB_EP_ATTR_BULK, USB_DIR_IN, EP2_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP3), USB_EP_ATTR_BULK, USB_DIR_OUT, EP3_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP4), USB_EP_ATTR_INT, USB_DIR_IN, EP4_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP5), USB_EP_ATTR_INT, USB_DIR_OUT, EP5_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP6), USB_EP_ATTR_BULK, USB_DIR_IN, EP6_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP7), USB_EP_ATTR_BULK, USB_DIR_OUT, EP7_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP8), USB_EP_ATTR_INT, USB_DIR_IN, EP8_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP9), USB_EP_ATTR_INT, USB_DIR_OUT, EP9_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP10), USB_EP_ATTR_BULK, USB_DIR_IN, EP10_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP11), USB_EP_ATTR_BULK, USB_DIR_OUT, EP11_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP12), USB_EP_ATTR_INT, USB_DIR_IN, EP12_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP13), USB_EP_ATTR_INT, USB_DIR_OUT, EP13_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP14), USB_EP_ATTR_BULK, USB_DIR_IN, EP14_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP15), USB_EP_ATTR_BULK, USB_DIR_OUT, EP15_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP16), USB_EP_ATTR_INT, USB_DIR_IN, EP16_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP17), USB_EP_ATTR_INT, USB_DIR_OUT, EP17_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP18), USB_EP_ATTR_BULK, USB_DIR_IN, EP18_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP19), USB_EP_ATTR_BULK, USB_DIR_OUT, EP19_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP20), USB_EP_ATTR_INT, USB_DIR_IN, EP20_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP21), USB_EP_ATTR_INT, USB_DIR_OUT, EP21_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP22), USB_EP_ATTR_BULK, USB_DIR_IN, EP22_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP23), USB_EP_ATTR_BULK, USB_DIR_OUT, EP23_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{EPADR_HW2SW(EP24), USB_EP_ATTR_INT, USB_DIR_IN, EP24_MAX_PKT_SIZE, ID_UNASSIGNED},
|
||
|
{0xFF, USB_EP_ATTR_TYPE_MASK, USB_DIR_MASK, 0, ID_ASSIGNED },
|
||
|
};
|
||
|
|
||
|
static struct ep_id *get_ep_entry(int ep_addr)
|
||
|
{
|
||
|
int i;
|
||
|
for (i = 0; i < sizeof(_ep_pool) / sizeof(_ep_pool[0]); i++)
|
||
|
{
|
||
|
if (_ep_pool[i].addr == EPADR_HW2SW(ep_addr))
|
||
|
return &_ep_pool[i];
|
||
|
}
|
||
|
return RT_NULL;
|
||
|
}
|
||
|
|
||
|
#define PRINT_EP_BASE(ep, base) rt_kprintf("%d: %08x\n", ep, USBD_GET_EP_BUF_ADDR(ep));
|
||
|
|
||
|
static void _nu_ep_partition(void)
|
||
|
{
|
||
|
int i;
|
||
|
uint32_t u32EPBufBase, u32EPBufLen;
|
||
|
|
||
|
/* Init setup packet buffer */
|
||
|
/* Buffer range for setup packet -> [0 ~ 0x7] */
|
||
|
USBD->STBUFSEG = SETUP_BUF_BASE;
|
||
|
|
||
|
/*****************************************************/
|
||
|
u32EPBufBase = SETUP_BUF_BASE + SETUP_BUF_LEN; //For EP0
|
||
|
|
||
|
/* EP0 ==> control IN endpoint, address 0 */
|
||
|
USBD_CONFIG_EP(EP0, USBD_CFG_CSTALL | USBD_CFG_EPMODE_IN | EPADR_HW2SW(EP0));
|
||
|
/* Buffer range for EP0 */
|
||
|
USBD_SET_EP_BUF_ADDR(EP0, u32EPBufBase);
|
||
|
|
||
|
u32EPBufLen = s_au32MaxPktSize[0]; //EP0 max pkt size
|
||
|
u32EPBufBase += u32EPBufLen;
|
||
|
|
||
|
/* EP1 ==> control OUT endpoint, address 0 */
|
||
|
USBD_CONFIG_EP(EP1, USBD_CFG_CSTALL | USBD_CFG_EPMODE_OUT | EPADR_HW2SW(EP1));
|
||
|
/* Buffer range for EP1 */
|
||
|
USBD_SET_EP_BUF_ADDR(EP1, u32EPBufBase);
|
||
|
|
||
|
u32EPBufLen = s_au32MaxPktSize[1]; //EP1 max pkt size
|
||
|
u32EPBufBase += u32EPBufLen;
|
||
|
/*****************************************************/
|
||
|
|
||
|
for (i = EP2; i < USBD_MAX_EP; i++)
|
||
|
{
|
||
|
uint32_t u32Config = EPADR_HW2SW(i);
|
||
|
struct ep_id *psEpId;
|
||
|
u32EPBufLen = s_au32MaxPktSize[i];
|
||
|
|
||
|
RT_ASSERT(u32EPBufBase <= 1536);
|
||
|
|
||
|
psEpId = get_ep_entry(i);
|
||
|
|
||
|
if (psEpId == RT_NULL)
|
||
|
continue;
|
||
|
|
||
|
switch (psEpId->dir)
|
||
|
{
|
||
|
case USB_DIR_IN:
|
||
|
u32Config |= USBD_CFG_EPMODE_IN;
|
||
|
break;
|
||
|
case USB_DIR_OUT:
|
||
|
u32Config |= USBD_CFG_EPMODE_OUT;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* Endpoint configuration */
|
||
|
USBD_CONFIG_EP(i, u32Config);
|
||
|
|
||
|
/* Buffer range for EP */
|
||
|
USBD_SET_EP_BUF_ADDR(i, u32EPBufBase);
|
||
|
|
||
|
//PRINT_EP_BASE(i, u32EPBufBase);
|
||
|
|
||
|
u32EPBufBase += u32EPBufLen;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static rt_err_t _ep_set_stall(rt_uint8_t address)
|
||
|
{
|
||
|
USBD_SET_EP_STALL(EPADR_SW2HW(address));
|
||
|
return RT_EOK;
|
||
|
}
|
||
|
|
||
|
static rt_err_t _ep_clear_stall(rt_uint8_t address)
|
||
|
{
|
||
|
USBD_ClearStall(EPADR_SW2HW(address));
|
||
|
|
||
|
return RT_EOK;
|
||
|
}
|
||
|
|
||
|
|
||
|
static rt_err_t _set_address(rt_uint8_t address)
|
||
|
{
|
||
|
if (0 != address)
|
||
|
{
|
||
|
nu_usbd_obj.address_tmp = address;
|
||
|
}
|
||
|
|
||
|
return RT_EOK;
|
||
|
}
|
||
|
|
||
|
static rt_err_t _set_config(rt_uint8_t address)
|
||
|
{
|
||
|
return RT_EOK;
|
||
|
}
|
||
|
|
||
|
static rt_err_t _ep_enable(uep_t ep)
|
||
|
{
|
||
|
RT_ASSERT(ep != RT_NULL);
|
||
|
RT_ASSERT(ep->ep_desc != RT_NULL);
|
||
|
|
||
|
USBD_CONFIG_EP(EPADR_SW2HW(EP_ADDRESS(ep)),
|
||
|
USBD_CFG_CSTALL
|
||
|
| ((EP_ADDRESS(ep) & USB_DIR_IN) ? USBD_CFG_EPMODE_IN : USBD_CFG_EPMODE_OUT)
|
||
|
| (EP_ADDRESS(ep) & USB_EPNO_MASK));
|
||
|
|
||
|
return RT_EOK;
|
||
|
}
|
||
|
|
||
|
static rt_err_t _ep_disable(uep_t ep)
|
||
|
{
|
||
|
RT_ASSERT(ep != RT_NULL);
|
||
|
RT_ASSERT(ep->ep_desc != RT_NULL);
|
||
|
|
||
|
USBD_CONFIG_EP(EPADR_SW2HW(EP_ADDRESS(ep)), USBD_CFG_EPMODE_DISABLE);
|
||
|
|
||
|
return RT_EOK;
|
||
|
}
|
||
|
|
||
|
static rt_size_t _ep_read(rt_uint8_t address, void *buffer)
|
||
|
{
|
||
|
rt_size_t size = 0;
|
||
|
rt_uint8_t *buf;
|
||
|
rt_uint32_t hw_ep_num = EPADR_SW2HW(address);
|
||
|
|
||
|
RT_ASSERT(!(address & USB_DIR_IN));
|
||
|
RT_ASSERT(buffer != RT_NULL);
|
||
|
|
||
|
size = USBD_GET_PAYLOAD_LEN(hw_ep_num);
|
||
|
buf = (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(hw_ep_num));
|
||
|
USBD_MemCopy(buffer, (uint8_t *)buf, size);
|
||
|
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
static rt_size_t _ep_read_prepare(rt_uint8_t address, void *buffer, rt_size_t size)
|
||
|
{
|
||
|
RT_ASSERT(!(address & USB_DIR_IN));
|
||
|
|
||
|
USBD_SET_PAYLOAD_LEN(EPADR_SW2HW(address), size);
|
||
|
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
static rt_size_t _ep_write(rt_uint8_t address, void *buffer, rt_size_t size)
|
||
|
{
|
||
|
RT_ASSERT((address & USB_DIR_IN));
|
||
|
|
||
|
/* even number is for IN endpoint */
|
||
|
rt_uint32_t hw_ep_num = EPADR_SW2HW(address);
|
||
|
uint8_t *buf;
|
||
|
buf = (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(hw_ep_num));
|
||
|
|
||
|
USBD_MemCopy(buf, (uint8_t *)buffer, size);
|
||
|
|
||
|
USBD_SET_PAYLOAD_LEN(hw_ep_num, size);
|
||
|
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
static rt_err_t _ep0_send_status(void)
|
||
|
{
|
||
|
/* Status stage */
|
||
|
USBD_SET_DATA1(EP0);
|
||
|
USBD_SET_PAYLOAD_LEN(EP0, 0);
|
||
|
return RT_EOK;
|
||
|
}
|
||
|
|
||
|
static rt_err_t _suspend(void)
|
||
|
{
|
||
|
return RT_EOK;
|
||
|
}
|
||
|
|
||
|
static rt_err_t _wakeup(void)
|
||
|
{
|
||
|
return RT_EOK;
|
||
|
}
|
||
|
|
||
|
__STATIC_INLINE void _USBD_IRQHandler(void)
|
||
|
{
|
||
|
rt_uint32_t u32IntSts = USBD_GET_INT_FLAG();
|
||
|
rt_uint32_t u32State = USBD_GET_BUS_STATE();
|
||
|
|
||
|
//------------------------------------------------------------------
|
||
|
if (u32IntSts & USBD_INTSTS_VBDETIF_Msk)
|
||
|
{
|
||
|
// Floating detect
|
||
|
USBD_CLR_INT_FLAG(USBD_INTSTS_VBDETIF_Msk);
|
||
|
|
||
|
if (USBD_IS_ATTACHED())
|
||
|
{
|
||
|
/* USB Plug In */
|
||
|
USBD_ENABLE_USB();
|
||
|
rt_usbd_connect_handler(&_rt_obj_udc);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* USB Unplug */
|
||
|
USBD_DISABLE_USB();
|
||
|
rt_usbd_disconnect_handler(&_rt_obj_udc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (u32IntSts & USBD_INTSTS_SOFIF_Msk)
|
||
|
{
|
||
|
USBD_CLR_INT_FLAG(USBD_INTSTS_SOFIF_Msk);
|
||
|
rt_usbd_sof_handler(&_rt_obj_udc);
|
||
|
}
|
||
|
//------------------------------------------------------------------
|
||
|
if (u32IntSts & USBD_INTSTS_BUSIF_Msk)
|
||
|
{
|
||
|
/* Clear event flag */
|
||
|
USBD_CLR_INT_FLAG(USBD_INTSTS_BUSIF_Msk);
|
||
|
|
||
|
if (u32State & USBD_ATTR_USBRST_Msk)
|
||
|
{
|
||
|
USBD_ENABLE_USB();
|
||
|
|
||
|
/* Reset PID DATA0 */
|
||
|
for (rt_uint32_t i = 0ul; i < USBD_MAX_EP; i++)
|
||
|
{
|
||
|
nu_usbd_obj.Instance->EP[i].CFG &= ~USBD_CFG_DSQSYNC_Msk;
|
||
|
}
|
||
|
|
||
|
/* Reset USB device address */
|
||
|
USBD_SET_ADDR(0ul);
|
||
|
|
||
|
/* Bus reset */
|
||
|
rt_usbd_reset_handler(&_rt_obj_udc);
|
||
|
}
|
||
|
if (u32State & USBD_ATTR_SUSPEND_Msk)
|
||
|
{
|
||
|
/* Enable USB but disable PHY */
|
||
|
USBD_DISABLE_PHY();
|
||
|
}
|
||
|
if (u32State & USBD_ATTR_RESUME_Msk)
|
||
|
{
|
||
|
/* Enable USB and enable PHY */
|
||
|
USBD_ENABLE_USB();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------
|
||
|
if (u32IntSts & USBD_INTSTS_WAKEUP)
|
||
|
{
|
||
|
/* Clear event flag */
|
||
|
USBD_CLR_INT_FLAG(USBD_INTSTS_WAKEUP);
|
||
|
USBD_ENABLE_USB();
|
||
|
}
|
||
|
|
||
|
if (u32IntSts & USBD_INTSTS_USBIF_Msk)
|
||
|
{
|
||
|
// USB event
|
||
|
if (u32IntSts & USBD_INTSTS_SETUP_Msk)
|
||
|
{
|
||
|
// Setup packet
|
||
|
/* Clear event flag */
|
||
|
USBD_CLR_INT_FLAG(USBD_INTSTS_SETUP_Msk);
|
||
|
|
||
|
/* Clear the data IN/OUT ready flag of control end-points */
|
||
|
USBD_STOP_TRANSACTION(EP0);
|
||
|
USBD_STOP_TRANSACTION(EP1);
|
||
|
|
||
|
USBD_SET_DATA1(EP0);
|
||
|
rt_usbd_ep0_setup_handler(&_rt_obj_udc, (struct urequest *)USBD_BUF_BASE);
|
||
|
}
|
||
|
|
||
|
/* Service EP events */
|
||
|
rt_uint32_t u32EpIntSts = USBD_GET_EP_INT_FLAG();
|
||
|
|
||
|
// EP events
|
||
|
if (u32EpIntSts & USBD_EPINTSTS_EPEVT0_Msk)
|
||
|
{
|
||
|
/* Clear event flag */
|
||
|
USBD_CLR_EP_INT_FLAG(USBD_EPINTSTS_EPEVT0_Msk);
|
||
|
|
||
|
if ((USBD_GET_ADDR() == 0)
|
||
|
&& (nu_usbd_obj.address_tmp)
|
||
|
)
|
||
|
{
|
||
|
USBD_SET_ADDR(nu_usbd_obj.address_tmp);
|
||
|
LOG_I("SET ADDR: 0x%02x", nu_usbd.address_tmp);
|
||
|
nu_usbd_obj.address_tmp = 0;
|
||
|
}
|
||
|
|
||
|
rt_usbd_ep0_in_handler(&_rt_obj_udc);
|
||
|
}
|
||
|
|
||
|
if (u32EpIntSts & USBD_EPINTSTS_EPEVT1_Msk)
|
||
|
{
|
||
|
/* Clear event flag */
|
||
|
USBD_CLR_EP_INT_FLAG(USBD_EPINTSTS_EPEVT1_Msk);
|
||
|
rt_usbd_ep0_out_handler(&_rt_obj_udc, 0);
|
||
|
}
|
||
|
|
||
|
/* For EP2 ~ EP24 */
|
||
|
{
|
||
|
rt_int32_t u32EpIrqIdx;
|
||
|
rt_int32_t u32EpIrqStatus = u32EpIntSts & (~((1 << EP2) - 1)); // Skip EP0/EP1 traveling.
|
||
|
|
||
|
// Find index of pin is attached in pool.
|
||
|
while ((u32EpIrqIdx = nu_ctz(u32EpIrqStatus)) < USBD_MAX_EP) // Count Trailing Zeros ==> Find First One
|
||
|
{
|
||
|
/* Clear event flag */
|
||
|
USBD_CLR_EP_INT_FLAG(1 << u32EpIrqIdx);
|
||
|
|
||
|
/* Report upper layer. */
|
||
|
rt_usbd_ep_in_handler(&_rt_obj_udc, _ep_pool[u32EpIrqIdx - 1].dir | EPADR_HW2SW(u32EpIrqIdx), 0);
|
||
|
u32EpIrqStatus &= ~(1 << u32EpIrqIdx);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void USBD_IRQHandler(void)
|
||
|
{
|
||
|
rt_interrupt_enter();
|
||
|
|
||
|
_USBD_IRQHandler();
|
||
|
|
||
|
rt_interrupt_leave();
|
||
|
}
|
||
|
|
||
|
static rt_err_t _init(rt_device_t device)
|
||
|
{
|
||
|
nu_usbd_t nu_usbd = (nu_usbd_t)device->user_data;
|
||
|
|
||
|
uint32_t u32RegLockBackup = SYS_IsRegLocked();
|
||
|
|
||
|
/* Initialize USB PHY */
|
||
|
SYS_UnlockReg();
|
||
|
/* Select USBD */
|
||
|
SYS->USBPHY = (SYS->USBPHY & ~SYS_USBPHY_USBROLE_Msk) | SYS_USBPHY_USBEN_Msk | SYS_USBPHY_SBO_Msk;
|
||
|
SYS_ResetModule(USBD_RST);
|
||
|
|
||
|
if (u32RegLockBackup)
|
||
|
SYS_LockReg();
|
||
|
|
||
|
_nu_ep_partition();
|
||
|
|
||
|
/* Initial USB engine */
|
||
|
/*
|
||
|
BYTEM=1: Byte mode: The size of the transfer from CPU to USB SRAM can be Byte only.
|
||
|
PWRDN=1: Turn-on related circuit of PHY transceiver.
|
||
|
DPPUEN=1: Pull-up resistor in USB_D+ bus Active.
|
||
|
*/
|
||
|
nu_usbd->Instance->ATTR = 0x7D0ul;
|
||
|
|
||
|
/* Force SE0 */
|
||
|
USBD_SET_SE0();
|
||
|
|
||
|
NVIC_EnableIRQ(USBD_IRQn);
|
||
|
|
||
|
USBD_Start();
|
||
|
|
||
|
return RT_EOK;
|
||
|
}
|
||
|
|
||
|
const static struct udcd_ops _udc_ops =
|
||
|
{
|
||
|
_set_address,
|
||
|
_set_config,
|
||
|
_ep_set_stall,
|
||
|
_ep_clear_stall,
|
||
|
_ep_enable,
|
||
|
_ep_disable,
|
||
|
_ep_read_prepare,
|
||
|
_ep_read,
|
||
|
_ep_write,
|
||
|
_ep0_send_status,
|
||
|
_suspend,
|
||
|
_wakeup,
|
||
|
};
|
||
|
|
||
|
#ifdef RT_USING_DEVICE_OPS
|
||
|
const static struct rt_device_ops _ops =
|
||
|
{
|
||
|
_init,
|
||
|
RT_NULL,
|
||
|
RT_NULL,
|
||
|
RT_NULL,
|
||
|
RT_NULL,
|
||
|
RT_NULL,
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
int nu_usbd_register(void)
|
||
|
{
|
||
|
if (RT_NULL != rt_device_find("usbd"))
|
||
|
{
|
||
|
LOG_E("\nUSBD Register failed. Another USBD device registered\n");
|
||
|
return -RT_ERROR;
|
||
|
}
|
||
|
|
||
|
rt_memset((void *)&_rt_obj_udc, 0, sizeof(struct udcd));
|
||
|
_rt_obj_udc.parent.type = RT_Device_Class_USBDevice;
|
||
|
|
||
|
#ifdef RT_USING_DEVICE_OPS
|
||
|
_rt_obj_udc.parent.ops = &_ops;
|
||
|
#else
|
||
|
_rt_obj_udc.parent.init = _init;
|
||
|
#endif
|
||
|
|
||
|
_rt_obj_udc.parent.user_data = &nu_usbd_obj;
|
||
|
_rt_obj_udc.ops = &_udc_ops;
|
||
|
|
||
|
/* Register endpoint information */
|
||
|
_rt_obj_udc.ep_pool = _ep_pool;
|
||
|
_rt_obj_udc.ep0.id = &_ep_pool[0];
|
||
|
|
||
|
_rt_obj_udc.device_is_hs = RT_FALSE; /* Support Full-Speed only */
|
||
|
|
||
|
rt_device_register((rt_device_t)&_rt_obj_udc, "usbd", 0);
|
||
|
|
||
|
return rt_usb_device_init();
|
||
|
}
|
||
|
INIT_DEVICE_EXPORT(nu_usbd_register);
|
||
|
#endif
|