905 lines
25 KiB
C
905 lines
25 KiB
C
/*
|
|
* Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2023-02-14 CDT first version
|
|
*/
|
|
|
|
/*******************************************************************************
|
|
* Include files
|
|
******************************************************************************/
|
|
#include <rtthread.h>
|
|
#include <rtdevice.h>
|
|
|
|
#if defined(BSP_USING_USBD)
|
|
|
|
//#define DRV_DEBUG
|
|
#define LOG_TAG "drv.usbd"
|
|
#include <drv_log.h>
|
|
|
|
#include "board_config.h"
|
|
#include "irq_config.h"
|
|
#include "drv_usbd.h"
|
|
|
|
extern rt_err_t rt_hw_usb_board_init(void);
|
|
extern void rt_hw_us_delay(rt_uint32_t us);
|
|
|
|
static usb_core_instance _hc32_usbd;
|
|
static struct udcd _hc32_udc;
|
|
|
|
|
|
static struct ep_id _ep_pool[] =
|
|
{
|
|
{0x0, USB_EP_ATTR_CONTROL, USB_DIR_INOUT, 64, ID_ASSIGNED },
|
|
{0x1, USB_EP_ATTR_BULK, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0x1, USB_EP_ATTR_BULK, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
{0x2, USB_EP_ATTR_BULK, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0x2, USB_EP_ATTR_BULK, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
{0x3, USB_EP_ATTR_BULK, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0x3, USB_EP_ATTR_BULK, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
{0x4, USB_EP_ATTR_INT, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0x4, USB_EP_ATTR_INT, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
{0x5, USB_EP_ATTR_ISOC, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0x5, USB_EP_ATTR_ISOC, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
#if defined (HC32F4A0)
|
|
{0x6, USB_EP_ATTR_BULK, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0x6, USB_EP_ATTR_BULK, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
{0x7, USB_EP_ATTR_BULK, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0x7, USB_EP_ATTR_BULK, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
{0x8, USB_EP_ATTR_BULK, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0x8, USB_EP_ATTR_BULK, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
{0x9, USB_EP_ATTR_BULK, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0x9, USB_EP_ATTR_BULK, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
{0xA, USB_EP_ATTR_BULK, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0xA, USB_EP_ATTR_BULK, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
{0xB, USB_EP_ATTR_INT, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0xB, USB_EP_ATTR_INT, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
{0xC, USB_EP_ATTR_INT, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0xC, USB_EP_ATTR_INT, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
{0xD, USB_EP_ATTR_INT, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0xD, USB_EP_ATTR_INT, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
{0xE, USB_EP_ATTR_ISOC, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0xE, USB_EP_ATTR_ISOC, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
{0xF, USB_EP_ATTR_ISOC, USB_DIR_IN, 64, ID_UNASSIGNED},
|
|
{0xF, USB_EP_ATTR_ISOC, USB_DIR_OUT, 64, ID_UNASSIGNED},
|
|
#endif
|
|
{0xFF, USB_EP_ATTR_TYPE_MASK, USB_DIR_MASK, 0, ID_ASSIGNED },
|
|
};
|
|
|
|
void usb_udelay(const uint32_t usec)
|
|
{
|
|
rt_hw_us_delay(usec);
|
|
}
|
|
|
|
void usb_mdelay(const uint32_t msec)
|
|
{
|
|
rt_thread_mdelay(msec);
|
|
}
|
|
|
|
static void usb_opendevep(usb_core_instance *pdev, uint8_t ep_addr, uint16_t ep_mps, uint8_t ep_type)
|
|
{
|
|
USB_DEV_EP *ep;
|
|
__IO uint8_t tmp_1, tmp_2;
|
|
|
|
tmp_1 = ep_addr >> 7; /* EP type, it is IN(=1) or OUT(=0) */
|
|
tmp_2 = ep_addr & 0x7FU; /* EP number */
|
|
if (tmp_1 == 1U)
|
|
{
|
|
ep = &pdev->dev.in_ep[tmp_2];
|
|
}
|
|
else
|
|
{
|
|
ep = &pdev->dev.out_ep[tmp_2];
|
|
}
|
|
|
|
ep->epidx = tmp_2;
|
|
|
|
ep->ep_dir = tmp_1;
|
|
ep->maxpacket = ep_mps;
|
|
ep->trans_type = ep_type;
|
|
if (tmp_1 == 1U)
|
|
{
|
|
/* Assign a Tx FIFO */
|
|
ep->tx_fifo_num = tmp_2;
|
|
}
|
|
/* Set initial data PID. */
|
|
if (ep_type == EP_TYPE_BULK)
|
|
{
|
|
ep->data_pid_start = 0U;
|
|
}
|
|
usb_epactive(&pdev->regs, ep);
|
|
}
|
|
|
|
static void usb_shutdevep(usb_core_instance *pdev, uint8_t ep_addr)
|
|
{
|
|
USB_DEV_EP *ep;
|
|
__IO uint8_t tmp_1, tmp_2;
|
|
|
|
tmp_1 = ep_addr >> 7; /* EP type, it is IN(=1) or OUT(=0) */
|
|
tmp_2 = ep_addr & 0x7FU; /* EP number */
|
|
if (tmp_1 == 1U)
|
|
{
|
|
ep = &pdev->dev.in_ep[tmp_2];
|
|
}
|
|
else
|
|
{
|
|
ep = &pdev->dev.out_ep[tmp_2];
|
|
}
|
|
ep->epidx = tmp_2;
|
|
ep->ep_dir = tmp_1;
|
|
usb_epdeactive(&pdev->regs, ep);
|
|
}
|
|
|
|
static void usb_readytorx(usb_core_instance *pdev, uint8_t ep_addr, uint8_t *pbuf, uint16_t buf_len)
|
|
{
|
|
USB_DEV_EP *ep;
|
|
__IO uint8_t tmp_1;
|
|
|
|
tmp_1 = ep_addr & 0x7FU; /* EP number */
|
|
ep = &pdev->dev.out_ep[tmp_1];
|
|
/* setup and start the Xfer */
|
|
ep->xfer_buff = pbuf;
|
|
ep->xfer_len = (uint32_t)buf_len;
|
|
ep->xfer_count = 0UL;
|
|
ep->ep_dir = 0U;
|
|
ep->epidx = tmp_1;
|
|
|
|
if (pdev->basic_cfgs.dmaen == 1U)
|
|
{
|
|
ep->dma_addr = (uint32_t)pbuf;
|
|
}
|
|
|
|
if (tmp_1 == 0U)
|
|
{
|
|
usb_ep0transbegin(&pdev->regs, ep, pdev->basic_cfgs.dmaen);
|
|
}
|
|
else
|
|
{
|
|
usb_epntransbegin(&pdev->regs, ep, pdev->basic_cfgs.dmaen);
|
|
}
|
|
}
|
|
|
|
static void usb_deveptx(usb_core_instance *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t buf_len)
|
|
{
|
|
USB_DEV_EP *ep;
|
|
__IO uint8_t tmp_1;
|
|
|
|
tmp_1 = ep_addr & 0x7FU; /* EP number */
|
|
ep = &pdev->dev.in_ep[tmp_1];
|
|
|
|
/* Setup and start the Transfer */
|
|
ep->ep_dir = 1U;
|
|
ep->epidx = tmp_1;
|
|
ep->xfer_buff = pbuf;
|
|
ep->dma_addr = (uint32_t)pbuf;
|
|
ep->xfer_count = 0UL;
|
|
ep->xfer_len = buf_len;
|
|
|
|
if (tmp_1 == 0U)
|
|
{
|
|
usb_ep0transbegin(&pdev->regs, ep, pdev->basic_cfgs.dmaen);
|
|
}
|
|
else
|
|
{
|
|
usb_epntransbegin(&pdev->regs, ep, pdev->basic_cfgs.dmaen);
|
|
}
|
|
}
|
|
|
|
static void usb_stalldevep(usb_core_instance *pdev, uint8_t epnum)
|
|
{
|
|
USB_DEV_EP *ep;
|
|
__IO uint8_t tmp_1, tmp_2;
|
|
|
|
tmp_1 = epnum >> 7; /* EP type, it is IN(=1) or OUT(=0) */
|
|
tmp_2 = epnum & 0x7FU; /* EP number */
|
|
|
|
if (tmp_1 != 0U)
|
|
{
|
|
ep = &pdev->dev.in_ep[tmp_2];
|
|
}
|
|
else
|
|
{
|
|
ep = &pdev->dev.out_ep[tmp_2];
|
|
}
|
|
|
|
ep->ep_stall = 1U;
|
|
ep->epidx = tmp_2;
|
|
if (tmp_1 != 0U)
|
|
{
|
|
ep->ep_dir = 1U;
|
|
}
|
|
else
|
|
{
|
|
ep->ep_dir = 0U;
|
|
}
|
|
|
|
usb_setepstall(&pdev->regs, ep);
|
|
}
|
|
|
|
static void usb_clrstall(usb_core_instance *pdev, uint8_t epnum)
|
|
{
|
|
USB_DEV_EP *ep;
|
|
__IO uint8_t tmp_1, tmp_2;
|
|
|
|
tmp_1 = epnum >> 7; /* EP type, it is IN(=1) or OUT(=0) */
|
|
tmp_2 = epnum & 0x7FU; /* EP number */
|
|
if (tmp_1 != 0U)
|
|
{
|
|
ep = &pdev->dev.in_ep[tmp_2];
|
|
}
|
|
else
|
|
{
|
|
ep = &pdev->dev.out_ep[tmp_2];
|
|
}
|
|
|
|
ep->ep_stall = 0U;
|
|
ep->epidx = tmp_2;
|
|
if (tmp_1 != 0U)
|
|
{
|
|
ep->ep_dir = 1U;
|
|
}
|
|
else
|
|
{
|
|
ep->ep_dir = 0U;
|
|
}
|
|
|
|
usb_clearepstall(&pdev->regs, ep);
|
|
}
|
|
|
|
static void usb_dev_rst(usb_core_instance *pdev)
|
|
{
|
|
usb_opendevep(pdev, 0x00U, USB_MAX_EP0_SIZE, EP_TYPE_CTRL);
|
|
usb_opendevep(pdev, 0x80U, USB_MAX_EP0_SIZE, EP_TYPE_CTRL);
|
|
rt_usbd_reset_handler(&_hc32_udc);
|
|
LOG_D("USB Reset");
|
|
}
|
|
|
|
static void usb_ctrlconn(usb_core_instance *pdev, uint8_t conn)
|
|
{
|
|
__IO uint8_t tmp_1;
|
|
tmp_1 = conn;
|
|
if (tmp_1 != 0U)
|
|
{
|
|
rt_usbd_connect_handler(&_hc32_udc);
|
|
LOG_D("USB Connect");
|
|
}
|
|
else
|
|
{
|
|
rt_usbd_disconnect_handler(&_hc32_udc);
|
|
LOG_D("USB Disconnect");
|
|
}
|
|
}
|
|
|
|
static void usb_dev_susp(usb_core_instance *pdev)
|
|
{
|
|
LOG_D("USB Suspend");
|
|
}
|
|
|
|
static void usb_dev_resume(usb_core_instance *pdev)
|
|
{
|
|
LOG_D("USB Resume");
|
|
}
|
|
|
|
static void usb_sof_process(usb_core_instance *pdev)
|
|
{
|
|
rt_usbd_sof_handler(&_hc32_udc);
|
|
}
|
|
|
|
static void usb_setup_process(usb_core_instance *pdev)
|
|
{
|
|
rt_usbd_ep0_setup_handler(&_hc32_udc, (struct urequest *)pdev->dev.setup_pkt_buf);
|
|
}
|
|
|
|
static void usb_dataout_process(usb_core_instance *pdev, uint8_t epnum)
|
|
{
|
|
if (epnum != 0)
|
|
{
|
|
rt_usbd_ep_out_handler(&_hc32_udc, epnum, pdev->dev.out_ep[epnum].xfer_count);
|
|
}
|
|
else
|
|
{
|
|
rt_usbd_ep0_out_handler(&_hc32_udc, pdev->dev.out_ep[0].xfer_count);
|
|
}
|
|
}
|
|
|
|
static void usb_datain_process(usb_core_instance *pdev, uint8_t epnum)
|
|
{
|
|
if (epnum == 0)
|
|
{
|
|
rt_usbd_ep0_in_handler(&_hc32_udc);
|
|
}
|
|
else
|
|
{
|
|
rt_usbd_ep_in_handler(&_hc32_udc, 0x80 | epnum, pdev->dev.in_ep[epnum].xfer_count);
|
|
}
|
|
}
|
|
|
|
static void usb_isoinincomplt_process(usb_core_instance *pdev)
|
|
{
|
|
/* reserved */
|
|
}
|
|
|
|
static void usb_isooutincomplt_process(usb_core_instance *pdev)
|
|
{
|
|
/* reserved */
|
|
}
|
|
|
|
static usb_dev_int_cbk_typedef dev_int_cbk =
|
|
{
|
|
&usb_dev_rst,
|
|
&usb_ctrlconn,
|
|
&usb_dev_susp,
|
|
&usb_dev_resume,
|
|
&usb_sof_process,
|
|
&usb_setup_process,
|
|
&usb_dataout_process,
|
|
&usb_datain_process,
|
|
&usb_isoinincomplt_process,
|
|
&usb_isooutincomplt_process
|
|
};
|
|
|
|
static usb_dev_int_cbk_typedef *dev_int_cbkpr = &dev_int_cbk;
|
|
|
|
static uint32_t usb_rddevinep(usb_core_instance *pdev, uint8_t epnum)
|
|
{
|
|
uint32_t u32diepmsk;
|
|
uint32_t u32diepempmsk;
|
|
u32diepmsk = READ_REG32(pdev->regs.DREGS->DIEPMSK);
|
|
u32diepempmsk = READ_REG32(pdev->regs.DREGS->DIEPEMPMSK);
|
|
u32diepmsk |= (((u32diepempmsk >> epnum) & 0x1UL) << 7U);
|
|
return (READ_REG32(pdev->regs.INEP_REGS[epnum]->DIEPINT) & u32diepmsk);
|
|
}
|
|
|
|
static void usb_wrblanktxfifo(usb_core_instance *pdev, uint32_t epnum)
|
|
{
|
|
USB_DEV_EP *ep;
|
|
uint32_t u32Len;
|
|
uint32_t u32Len32b;
|
|
uint16_t u16spclen;
|
|
uint32_t u32diepempmsk;
|
|
|
|
ep = &pdev->dev.in_ep[epnum];
|
|
u32Len = ep->xfer_len - ep->xfer_count;
|
|
if (u32Len > ep->maxpacket)
|
|
{
|
|
u32Len = ep->maxpacket;
|
|
}
|
|
u32Len32b = (u32Len + 3UL) >> 2;
|
|
u16spclen = usb_rdineptxfspcavail(pdev, epnum);
|
|
while ((u16spclen >= u32Len32b) && (ep->xfer_count < ep->xfer_len))
|
|
{
|
|
u32Len = ep->xfer_len - ep->xfer_count;
|
|
|
|
if (u32Len > ep->maxpacket)
|
|
{
|
|
u32Len = ep->maxpacket;
|
|
}
|
|
u32Len32b = (u32Len + 3UL) >> 2;
|
|
usb_wrpkt(&pdev->regs, ep->xfer_buff, (uint8_t)epnum, (uint16_t)u32Len, pdev->basic_cfgs.dmaen);
|
|
ep->xfer_buff += u32Len;
|
|
ep->xfer_count += u32Len;
|
|
u16spclen = usb_rdineptxfspcavail(pdev, epnum);
|
|
}
|
|
|
|
if (u32Len == 0UL)
|
|
{
|
|
u32diepempmsk = 0x01UL << epnum;
|
|
CLR_REG32_BIT(pdev->regs.DREGS->DIEPEMPMSK, u32diepempmsk);
|
|
}
|
|
}
|
|
|
|
#ifdef VBUS_SENSING_ENABLED
|
|
static void usb_sessionrequest_isr(usb_core_instance *pdev)
|
|
{
|
|
dev_int_cbkpr->devctrlconnect(pdev, 1U);
|
|
|
|
WRITE_REG32(pdev->regs.GREGS->GINTSTS, USBFS_GINTSTS_VBUSVINT);
|
|
|
|
if (0U != pdev->basic_cfgs.low_power)
|
|
{
|
|
CLR_REG32_BIT(*pdev->regs.GCCTL, USBFS_GCCTL_STPPCLK | USBFS_GCCTL_GATEHCLK);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void usb_resume_isr(usb_core_instance *pdev)
|
|
{
|
|
if (0U != pdev->basic_cfgs.low_power)
|
|
{
|
|
CLR_REG32_BIT(*pdev->regs.GCCTL, USBFS_GCCTL_STPPCLK | USBFS_GCCTL_GATEHCLK);
|
|
}
|
|
|
|
CLR_REG32_BIT(pdev->regs.DREGS->DCTL, USBFS_DCTL_RWUSIG);
|
|
|
|
dev_int_cbkpr->Resume(pdev);
|
|
|
|
WRITE_REG32(pdev->regs.GREGS->GINTSTS, USBFS_GINTSTS_WKUINT);
|
|
}
|
|
|
|
static void usb_susp_isr(usb_core_instance *pdev)
|
|
{
|
|
uint32_t u32dsts;
|
|
|
|
u32dsts = READ_REG32(pdev->regs.DREGS->DSTS);
|
|
if ((u32dsts & 1UL) != 0UL)
|
|
{
|
|
dev_int_cbkpr->Suspend(pdev);
|
|
}
|
|
WRITE_REG32(pdev->regs.GREGS->GINTSTS, USBFS_GINTSTS_USBSUSP);
|
|
}
|
|
|
|
static void usb_inep_isr(usb_core_instance *pdev)
|
|
{
|
|
uint32_t u32diepint;
|
|
uint32_t u32EpIntr;
|
|
uint8_t u8epnum;
|
|
uint32_t u32diepempmsk;
|
|
|
|
u32EpIntr = usb_getalliepintr(&pdev->regs);
|
|
u8epnum = 0U;
|
|
while ((0U != u32EpIntr) && (u8epnum < USB_MAX_TX_FIFOS))
|
|
{
|
|
if ((u32EpIntr & 0x1UL) != 0UL)
|
|
{
|
|
u32diepint = usb_rddevinep(pdev, u8epnum);
|
|
if ((u32diepint & XFER_COMPL) != 0UL)
|
|
{
|
|
u32diepempmsk = 1UL << u8epnum;
|
|
CLR_REG32_BIT(pdev->regs.DREGS->DIEPEMPMSK, u32diepempmsk);
|
|
WRITE_REG32(pdev->regs.INEP_REGS[u8epnum]->DIEPINT, XFER_COMPL);
|
|
dev_int_cbkpr->DataInStage(pdev, u8epnum);
|
|
if (pdev->basic_cfgs.dmaen == 1U)
|
|
{
|
|
if ((pdev->dev.device_state == USB_EP0_STATUS_IN) && (u8epnum == 0U))
|
|
{
|
|
pdev->dev.out_ep[0].xfer_len = 64U;
|
|
pdev->dev.out_ep[0].rem_data_len = 64U;
|
|
pdev->dev.out_ep[0].total_data_len = 64U;
|
|
usb_ep0revcfg(&pdev->regs, pdev->basic_cfgs.dmaen, pdev->dev.setup_pkt_buf);
|
|
pdev->dev.device_state = USB_EP0_IDLE;
|
|
}
|
|
}
|
|
}
|
|
if ((u32diepint & EPDISABLED) != 0UL)
|
|
{
|
|
WRITE_REG32(pdev->regs.INEP_REGS[u8epnum]->DIEPINT, EPDISABLED);
|
|
}
|
|
if ((u32diepint & TIME_OUT) != 0UL)
|
|
{
|
|
WRITE_REG32(pdev->regs.INEP_REGS[u8epnum]->DIEPINT, TIME_OUT);
|
|
}
|
|
if ((u32diepint & INTKNTXFEMP) != 0UL)
|
|
{
|
|
WRITE_REG32(pdev->regs.INEP_REGS[u8epnum]->DIEPINT, INTKNTXFEMP);
|
|
}
|
|
if ((u32diepint & INEPNAKEFF) != 0UL)
|
|
{
|
|
WRITE_REG32(pdev->regs.INEP_REGS[u8epnum]->DIEPINT, INEPNAKEFF);
|
|
}
|
|
if ((u32diepint & TXFEMP) != 0UL)
|
|
{
|
|
usb_wrblanktxfifo(pdev, u8epnum);
|
|
WRITE_REG32(pdev->regs.INEP_REGS[u8epnum]->DIEPINT, TXFEMP);
|
|
}
|
|
}
|
|
u8epnum++;
|
|
u32EpIntr >>= 1U;
|
|
}
|
|
}
|
|
|
|
static void usb_outep_isr(usb_core_instance *pdev)
|
|
{
|
|
uint32_t u32EpIntr;
|
|
uint32_t u32doepint;
|
|
uint8_t u8epnum = 0U;
|
|
uint32_t u8Xfer;
|
|
uint32_t u32ReadEpSize;
|
|
|
|
u32EpIntr = usb_getalloepintr(&pdev->regs);
|
|
while ((u32EpIntr != 0UL) && (u8epnum < USB_MAX_TX_FIFOS))
|
|
{
|
|
if ((u32EpIntr & 0x1UL) != 0UL)
|
|
{
|
|
u32doepint = usb_getoepintbit(&pdev->regs, u8epnum);
|
|
if ((u32doepint & XFER_COMPL) != 0UL)
|
|
{
|
|
WRITE_REG32(pdev->regs.OUTEP_REGS[u8epnum]->DOEPINT, XFER_COMPL);
|
|
if (pdev->basic_cfgs.dmaen == 1U)
|
|
{
|
|
u32ReadEpSize = (READ_REG32(pdev->regs.OUTEP_REGS[u8epnum]->DOEPTSIZ) & USBFS_DOEPTSIZ_XFRSIZ);
|
|
u8Xfer = LL_MIN(pdev->dev.out_ep[u8epnum].maxpacket, pdev->dev.out_ep[u8epnum].xfer_len);
|
|
pdev->dev.out_ep[u8epnum].xfer_count = u8Xfer - u32ReadEpSize;
|
|
if (u8epnum != 0U)
|
|
{
|
|
pdev->dev.out_ep[u8epnum].xfer_count = pdev->dev.out_ep[u8epnum].xfer_len - u32ReadEpSize;
|
|
}
|
|
}
|
|
dev_int_cbkpr->DataOutStage(pdev, u8epnum);
|
|
if (pdev->basic_cfgs.dmaen == 1U)
|
|
{
|
|
if ((pdev->dev.device_state == USB_EP0_STATUS_OUT) && (u8epnum == 0U))
|
|
{
|
|
pdev->dev.out_ep[0].xfer_len = 64U;
|
|
pdev->dev.out_ep[0].rem_data_len = 64U;
|
|
pdev->dev.out_ep[0].total_data_len = 64U;
|
|
usb_ep0revcfg(&pdev->regs, pdev->basic_cfgs.dmaen, pdev->dev.setup_pkt_buf);
|
|
pdev->dev.device_state = USB_EP0_IDLE;
|
|
}
|
|
}
|
|
}
|
|
if ((u32doepint & EPDISABLED) != 0UL)
|
|
{
|
|
WRITE_REG32(pdev->regs.OUTEP_REGS[u8epnum]->DOEPINT, EPDISABLED);
|
|
}
|
|
if (u8epnum == 0U)
|
|
{
|
|
u32doepint = usb_getoepintbit(&pdev->regs, u8epnum);
|
|
if ((u32doepint & SETUP_BIT) != 0UL)
|
|
{
|
|
dev_int_cbkpr->SetupStage(pdev);
|
|
WRITE_REG32(pdev->regs.OUTEP_REGS[u8epnum]->DOEPINT, SETUP_BIT);
|
|
}
|
|
}
|
|
}
|
|
u8epnum++;
|
|
u32EpIntr >>= 1U;
|
|
}
|
|
}
|
|
|
|
static void usb_sof_isr(usb_core_instance *pdev)
|
|
{
|
|
dev_int_cbkpr->SOF(pdev);
|
|
WRITE_REG32(pdev->regs.GREGS->GINTSTS, USBFS_GINTSTS_SOF);
|
|
}
|
|
|
|
static void usb_rxstsqlvl_isr(usb_core_instance *pdev)
|
|
{
|
|
uint32_t u32grxsts;
|
|
USB_DEV_EP *ep;
|
|
uint8_t u8epnum;
|
|
uint8_t u8PktStatus;
|
|
uint16_t u16ByteCnt;
|
|
|
|
CLR_REG32_BIT(pdev->regs.GREGS->GINTMSK, USBFS_GINTMSK_RXFNEM);
|
|
|
|
u32grxsts = READ_REG32(pdev->regs.GREGS->GRXSTSP);
|
|
u8epnum = (uint8_t)(u32grxsts & USBFS_GRXSTSP_CHNUM_EPNUM);
|
|
u8PktStatus = (uint8_t)((u32grxsts & USBFS_GRXSTSP_PKTSTS) >> USBFS_GRXSTSP_PKTSTS_POS);
|
|
u16ByteCnt = (uint16_t)((u32grxsts & USBFS_GRXSTSP_BCNT) >> USBFS_GRXSTSP_BCNT_POS);
|
|
ep = &pdev->dev.out_ep[u8epnum];
|
|
switch (u8PktStatus)
|
|
{
|
|
case STS_DATA_UPDT:
|
|
if (0U != u16ByteCnt)
|
|
{
|
|
usb_rdpkt(&pdev->regs, ep->xfer_buff, u16ByteCnt);
|
|
ep->xfer_buff += u16ByteCnt;
|
|
ep->xfer_count += u16ByteCnt;
|
|
}
|
|
else
|
|
{
|
|
;
|
|
}
|
|
break;
|
|
case STS_SETUP_UPDT:
|
|
/* Copy the setup packet received in FIFO into the setup buffer in RAM */
|
|
usb_rdpkt(&pdev->regs, pdev->dev.setup_pkt_buf, 8U);
|
|
ep->xfer_count += u16ByteCnt;
|
|
break;
|
|
case STS_GOUT_NAK:
|
|
case STS_XFER_COMP:
|
|
case STS_SETUP_COMP:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
SET_REG32_BIT(pdev->regs.GREGS->GINTMSK, USBFS_GINTMSK_RXFNEM);
|
|
}
|
|
|
|
static void usb_reset_isr(usb_core_instance *pdev)
|
|
{
|
|
uint32_t i;
|
|
|
|
CLR_REG32_BIT(pdev->regs.DREGS->DCTL, USBFS_DCTL_RWUSIG);
|
|
usb_txfifoflush(&pdev->regs, 0UL);
|
|
for (i = 0UL; i < pdev->basic_cfgs.dev_epnum ; i++)
|
|
{
|
|
WRITE_REG32(pdev->regs.INEP_REGS[i]->DIEPINT, 0xFFUL);
|
|
WRITE_REG32(pdev->regs.OUTEP_REGS[i]->DOEPINT, 0xFFUL);
|
|
}
|
|
WRITE_REG32(pdev->regs.DREGS->DAINT, 0xFFFFFFFFUL);
|
|
WRITE_REG32(pdev->regs.DREGS->DAINTMSK, 1UL | (1UL << USBFS_DAINTMSK_OEPINTM_POS));
|
|
|
|
WRITE_REG32(pdev->regs.DREGS->DOEPMSK, USBFS_DOEPMSK_STUPM | USBFS_DOEPMSK_XFRCM | USBFS_DOEPMSK_EPDM);
|
|
#ifdef USB_OTG_HS_DEDICATED_EP1_ENABLED
|
|
WRITE_REG32(pdev->regs.DREGS->DOUTEP1MSK, USBFS_DOEPMSK_STUPM | USBFS_DOEPMSK_XFRCM | USBFS_DOEPMSK_EPDM);
|
|
#endif
|
|
|
|
WRITE_REG32(pdev->regs.DREGS->DIEPMSK, USBFS_DIEPMSK_XFRCM | USBFS_DIEPMSK_TOM | USBFS_DIEPMSK_EPDM);
|
|
#ifdef USB_OTG_HS_DEDICATED_EP1_ENABLED
|
|
WRITE_REG32(pdev->regs.DREGS->DINEP1MSK, USBFS_DIEPMSK_XFRCM | USBFS_DIEPMSK_TOM | USBFS_DIEPMSK_EPDM);
|
|
#endif
|
|
|
|
CLR_REG32_BIT(pdev->regs.DREGS->DCFG, USBFS_DCFG_DAD);
|
|
pdev->dev.out_ep[0].xfer_len = 64U;
|
|
pdev->dev.out_ep[0].rem_data_len = 64U;
|
|
pdev->dev.out_ep[0].total_data_len = 64U;
|
|
usb_ep0revcfg(&pdev->regs, pdev->basic_cfgs.dmaen, pdev->dev.setup_pkt_buf);
|
|
WRITE_REG32(pdev->regs.GREGS->GINTSTS, USBFS_GINTSTS_USBRST);
|
|
|
|
dev_int_cbkpr->Reset(pdev);
|
|
}
|
|
|
|
static void usb_enumfinish_isr(usb_core_instance *pdev)
|
|
{
|
|
usb_ep0activate(&pdev->regs);
|
|
usb_setaroundtim(pdev);
|
|
WRITE_REG32(pdev->regs.GREGS->GINTSTS, USBFS_GINTSTS_ENUMDNE);
|
|
}
|
|
|
|
static void usb_isoinincomplt_isr(usb_core_instance *pdev)
|
|
{
|
|
dev_int_cbkpr->IsoINIncomplete(pdev);
|
|
WRITE_REG32(pdev->regs.GREGS->GINTSTS, USBFS_GINTSTS_IISOIXFR);
|
|
}
|
|
|
|
static void usb_isooutincomplt_isr(usb_core_instance *pdev)
|
|
{
|
|
dev_int_cbkpr->IsoOUTIncomplete(pdev);
|
|
WRITE_REG32(pdev->regs.GREGS->GINTSTS, USBFS_GINTSTS_IPXFR_INCOMPISOOUT);
|
|
}
|
|
|
|
static void usb_isr_handler(usb_core_instance *pdev)
|
|
{
|
|
uint32_t u32gintsts;
|
|
|
|
if (0U == usb_getcurmod(&pdev->regs))
|
|
{
|
|
u32gintsts = usb_getcoreintr(&pdev->regs);
|
|
if (u32gintsts == 0UL)
|
|
{
|
|
return;
|
|
}
|
|
if ((u32gintsts & OUTEP_INT) != 0UL)
|
|
{
|
|
usb_outep_isr(pdev);
|
|
}
|
|
if ((u32gintsts & INEP_INT) != 0UL)
|
|
{
|
|
usb_inep_isr(pdev);
|
|
}
|
|
if ((u32gintsts & MODEMIS_INT) != 0UL)
|
|
{
|
|
WRITE_REG32(pdev->regs.GREGS->GINTSTS, MODEMIS_INT);
|
|
}
|
|
if ((u32gintsts & WAKEUP_INT) != 0UL)
|
|
{
|
|
usb_resume_isr(pdev);
|
|
}
|
|
if ((u32gintsts & USBSUSP_INT) != 0UL)
|
|
{
|
|
usb_susp_isr(pdev);
|
|
}
|
|
if ((u32gintsts & SOF_INT) != 0UL)
|
|
{
|
|
usb_sof_isr(pdev);
|
|
}
|
|
if ((u32gintsts & RXFLVL_INT) != 0UL)
|
|
{
|
|
usb_rxstsqlvl_isr(pdev);
|
|
}
|
|
if ((u32gintsts & USBRST_INT) != 0UL)
|
|
{
|
|
usb_reset_isr(pdev);
|
|
}
|
|
if ((u32gintsts & ENUMDONE_INT) != 0UL)
|
|
{
|
|
usb_enumfinish_isr(pdev);
|
|
}
|
|
if ((u32gintsts & INCOMPLSOIN) != 0UL)
|
|
{
|
|
usb_isoinincomplt_isr(pdev);
|
|
}
|
|
if ((u32gintsts & INCOMPLSOOUT) != 0UL)
|
|
{
|
|
usb_isooutincomplt_isr(pdev);
|
|
}
|
|
#ifdef VBUS_SENSING_ENABLED
|
|
if ((u32gintsts & VBUSV_INT) != 0UL)
|
|
{
|
|
usb_sessionrequest_isr(pdev);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void usbd_irq_handler(void)
|
|
{
|
|
rt_interrupt_enter();
|
|
usb_isr_handler(&_hc32_usbd);
|
|
rt_interrupt_leave();
|
|
}
|
|
|
|
static rt_err_t _usbd_ep_set_stall(rt_uint8_t address)
|
|
{
|
|
usb_stalldevep(&_hc32_usbd, address);
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _usbd_ep_clear_stall(rt_uint8_t address)
|
|
{
|
|
usb_clrstall(&_hc32_usbd, address);
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _usbd_set_address(rt_uint8_t address)
|
|
{
|
|
usb_devaddrset(&_hc32_usbd.regs, address);
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _usbd_set_config(rt_uint8_t address)
|
|
{
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _usbd_ep_enable(uep_t ep)
|
|
{
|
|
RT_ASSERT(ep != RT_NULL);
|
|
RT_ASSERT(ep->ep_desc != RT_NULL);
|
|
usb_opendevep(&_hc32_usbd, ep->ep_desc->bEndpointAddress,
|
|
ep->ep_desc->wMaxPacketSize, ep->ep_desc->bmAttributes);
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _usbd_ep_disable(uep_t ep)
|
|
{
|
|
RT_ASSERT(ep != RT_NULL);
|
|
RT_ASSERT(ep->ep_desc != RT_NULL);
|
|
usb_shutdevep(&_hc32_usbd, ep->ep_desc->bEndpointAddress);
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_size_t _usbd_ep_read(rt_uint8_t address, void *buffer)
|
|
{
|
|
rt_size_t size = 0;
|
|
RT_ASSERT(buffer != RT_NULL);
|
|
return size;
|
|
}
|
|
|
|
static rt_size_t _usbd_ep_read_prepare(rt_uint8_t address, void *buffer, rt_size_t size)
|
|
{
|
|
usb_readytorx(&_hc32_usbd, address, buffer, size);
|
|
return size;
|
|
}
|
|
|
|
static rt_size_t _usbd_ep_write(rt_uint8_t address, void *buffer, rt_size_t size)
|
|
{
|
|
usb_deveptx(&_hc32_usbd, address, buffer, size);
|
|
return size;
|
|
}
|
|
|
|
static rt_err_t _usbd_ep0_send_status(void)
|
|
{
|
|
usb_deveptx(&_hc32_usbd, 0x00, NULL, 0);
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _usbd_suspend(void)
|
|
{
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _usbd_wakeup(void)
|
|
{
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _usbd_init(rt_device_t device)
|
|
{
|
|
usb_core_instance *pdev;
|
|
stc_usb_port_identify stcPortIdentify;
|
|
struct hc32_irq_config irq_config;
|
|
|
|
pdev = (usb_core_instance *)device->user_data;
|
|
rt_hw_usb_board_init();
|
|
#if !defined(BSP_USING_USBHS)
|
|
FCG_Fcg1PeriphClockCmd(FCG1_PERIPH_USBFS, ENABLE);
|
|
#else
|
|
FCG_Fcg1PeriphClockCmd(FCG1_PERIPH_USBHS, ENABLE);
|
|
#endif
|
|
/* Parameters */
|
|
#if !defined(BSP_USING_USBHS)
|
|
stcPortIdentify.u8CoreID = USBFS_CORE_ID;
|
|
#else
|
|
stcPortIdentify.u8CoreID = USBHS_CORE_ID;
|
|
#endif
|
|
#if defined (HC32F4A0)
|
|
#if !defined(BSP_USING_USBHS_PHY_EXTERN)
|
|
stcPortIdentify.u8PhyType = USBHS_PHY_EMBED;
|
|
#else
|
|
stcPortIdentify.u8PhyType = USBHS_PHY_EXT;
|
|
#endif
|
|
#endif
|
|
usb_setregaddr(&pdev->regs, &stcPortIdentify, &pdev->basic_cfgs);
|
|
|
|
usb_gintdis(&pdev->regs);
|
|
/*Init the Core (common init.) */
|
|
usb_initusbcore(&pdev->regs, &pdev->basic_cfgs);
|
|
/* Force Device Mode*/
|
|
usb_modeset(&pdev->regs, DEVICE_MODE);
|
|
/* Init Device */
|
|
usb_devmodeinit(&pdev->regs, &pdev->basic_cfgs);
|
|
/* Enable USB Global interrupt */
|
|
usb_ginten(&pdev->regs);
|
|
/* NVIC Config */
|
|
irq_config.irq_num = BSP_USB_GLB_IRQ_NUM;
|
|
#if !defined(BSP_USING_USBHS)
|
|
irq_config.int_src = INT_SRC_USBFS_GLB;
|
|
#else
|
|
irq_config.int_src = INT_SRC_USBHS_GLB;
|
|
#endif
|
|
irq_config.irq_prio = BSP_USB_GLB_IRQ_PRIO;
|
|
/* register interrupt */
|
|
hc32_install_irq_handler(&irq_config,
|
|
usbd_irq_handler,
|
|
RT_TRUE);
|
|
return RT_EOK;
|
|
}
|
|
|
|
const static struct udcd_ops _udc_ops =
|
|
{
|
|
_usbd_set_address,
|
|
_usbd_set_config,
|
|
_usbd_ep_set_stall,
|
|
_usbd_ep_clear_stall,
|
|
_usbd_ep_enable,
|
|
_usbd_ep_disable,
|
|
_usbd_ep_read_prepare,
|
|
_usbd_ep_read,
|
|
_usbd_ep_write,
|
|
_usbd_ep0_send_status,
|
|
_usbd_suspend,
|
|
_usbd_wakeup,
|
|
};
|
|
|
|
#ifdef RT_USING_DEVICE_OPS
|
|
const static struct rt_device_ops _ops =
|
|
{
|
|
_usbd_init,
|
|
RT_NULL,
|
|
RT_NULL,
|
|
RT_NULL,
|
|
RT_NULL,
|
|
RT_NULL,
|
|
};
|
|
#endif
|
|
|
|
int rt_hw_usbd_init(void)
|
|
{
|
|
rt_memset((void *)&_hc32_udc, 0, sizeof(struct udcd));
|
|
_hc32_udc.parent.type = RT_Device_Class_USBDevice;
|
|
#ifdef RT_USING_DEVICE_OPS
|
|
_hc32_udc.parent.ops = &_ops;
|
|
#else
|
|
_hc32_udc.parent.init = _usbd_init;
|
|
#endif
|
|
_hc32_udc.parent.user_data = &_hc32_usbd;
|
|
_hc32_udc.ops = &_udc_ops;
|
|
/* Register endpoint infomation */
|
|
_hc32_udc.ep_pool = _ep_pool;
|
|
_hc32_udc.ep0.id = &_ep_pool[0];
|
|
#ifdef BSP_USBD_SPEED_HS
|
|
_hc32_udc.device_is_hs = RT_TRUE;
|
|
#endif
|
|
rt_device_register((rt_device_t)&_hc32_udc, "usbd", 0);
|
|
rt_usb_device_init();
|
|
return RT_EOK;
|
|
}
|
|
INIT_DEVICE_EXPORT(rt_hw_usbd_init);
|
|
|
|
#endif /* BSP_USING_USBD */
|