diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_core.h b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_core.h new file mode 100644 index 0000000..70563ec --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_core.h @@ -0,0 +1,117 @@ +/*! + \file drv_usb_core.h + \brief USB core low level driver header file + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#ifndef __DRV_USB_CORE_H +#define __DRV_USB_CORE_H + +#include "drv_usb_regs.h" +#include "usb_ch9_std.h" + +#define USB_FS_EP0_MAX_LEN 64U /* maximum packet size of EndPoint0 */ + +#define HC_MAX_PACKET_COUNT 140U /* maximum packet count */ + +#define EP_ID(x) ((uint8_t)((x) & 0x7FU)) /* endpoint number */ +#define EP_DIR(x) ((uint8_t)((x) >> 7)) /* endpoint direction */ + +enum _usb_eptype { + USB_EPTYPE_CTRL = 0U, /*!< control endpoint type */ + USB_EPTYPE_ISOC = 1U, /*!< isochronous endpoint type */ + USB_EPTYPE_BULK = 2U, /*!< bulk endpoint type */ + USB_EPTYPE_INTR = 3U, /*!< interrupt endpoint type */ + USB_EPTYPE_MASK = 3U, /*!< endpoint type mask */ +}; + +typedef enum +{ + USB_OTG_OK = 0, /*!< USB OTG status OK*/ + USB_OTG_FAIL /*!< USB OTG status fail*/ +} usb_otg_status; + +typedef enum +{ + USB_OK = 0, /*!< USB status OK*/ + USB_FAIL /*!< USB status fail*/ +} usb_status; + +typedef enum +{ + USB_USE_FIFO, /*!< USB use FIFO transfer mode */ + USB_USE_DMA /*!< USB use DMA transfer mode */ +} usb_transfer_mode; + +typedef struct +{ + uint8_t core_enum; /*!< USB core type */ + uint8_t core_speed; /*!< USB core speed */ + uint8_t num_pipe; /*!< USB host channel numbers */ + uint8_t num_ep; /*!< USB device endpoint numbers */ + uint8_t transfer_mode; /*!< USB transfer mode */ + uint8_t phy_itf; /*!< USB core PHY interface */ + uint8_t sof_enable; /*!< USB SOF output */ + uint8_t low_power; /*!< USB low power */ +} usb_core_basic; + +/* function declarations */ + +/* config core capabilities */ +usb_status usb_basic_init (usb_core_basic *usb_basic, + usb_core_regs *usb_regs, + usb_core_enum usb_core); + +/*initializes the USB controller registers and prepares the core device mode or host mode operation*/ +usb_status usb_core_init (usb_core_basic usb_basic, usb_core_regs *usb_regs); + +/* read a packet from the Rx FIFO associated with the endpoint */ +void *usb_rxfifo_read (usb_core_regs *core_regs, uint8_t *dest_buf, uint16_t byte_count); + +/* write a packet into the Tx FIFO associated with the endpoint */ +usb_status usb_txfifo_write (usb_core_regs *usb_regs, + uint8_t *src_buf, + uint8_t fifo_num, + uint16_t byte_count); + +/* flush a Tx FIFO or all Tx FIFOs */ +usb_status usb_txfifo_flush (usb_core_regs *usb_regs, uint8_t fifo_num); + +/* flush the entire Rx FIFO */ +usb_status usb_rxfifo_flush (usb_core_regs *usb_regs); + +/* get the global interrupts */ +static inline uint32_t usb_coreintr_get(usb_core_regs *usb_regs) +{ + return usb_regs->gr->GINTEN & usb_regs->gr->GINTF; +} + +#endif /* __DRV_USB_CORE_H */ diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_dev.h b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_dev.h new file mode 100644 index 0000000..6b85712 --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_dev.h @@ -0,0 +1,217 @@ +/*! + \file drv_usb_dev.h + \brief USB device low level driver header file + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#ifndef __DRV_USB_DEV_H +#define __DRV_USB_DEV_H + +#include "drv_usb_core.h" + +enum usb_ctl_status { + USB_CTL_IDLE = 0U, /*!< USB control transfer idle state */ + USB_CTL_DATA_IN, /*!< USB control transfer data in state */ + USB_CTL_LAST_DATA_IN, /*!< USB control transfer last data in state */ + USB_CTL_DATA_OUT, /*!< USB control transfer data out state */ + USB_CTL_LAST_DATA_OUT, /*!< USB control transfer last data out state */ + USB_CTL_STATUS_IN, /*!< USB control transfer status in state*/ + USB_CTL_STATUS_OUT /*!< USB control transfer status out state */ +}; + +#define EP_IN(x) ((uint8_t)(0x80U | (x))) /*!< device IN endpoint */ +#define EP_OUT(x) ((uint8_t)(x)) /*!< device OUT endpoint */ + +/* USB descriptor */ +typedef struct _usb_desc { + uint8_t *dev_desc; /*!< device descriptor */ + uint8_t *config_desc; /*!< config descriptor */ + uint8_t *bos_desc; /*!< BOS descriptor */ + + void* const *strings; /*!< string descriptor */ +} usb_desc; + +/* USB power management */ +typedef struct _usb_pm { + uint8_t power_mode; /*!< power mode */ + uint8_t power_low; /*!< power low */ + uint8_t dev_remote_wakeup; /*!< remote wakeup */ + uint8_t remote_wakeup_on; /*!< remote wakeup on */ +} usb_pm; + +/* USB control information */ +typedef struct _usb_control { + usb_req req; /*!< USB standard device request */ + + uint8_t ctl_state; /*!< USB control transfer state */ + uint8_t ctl_zlp; /*!< zero lenth package */ +} usb_control; + +typedef struct +{ + struct { + uint8_t num: 4; /*!< the endpoint number.it can be from 0 to 6 */ + uint8_t pad: 3; /*!< padding between number and direction */ + uint8_t dir: 1; /*!< the endpoint direction */ + } ep_addr; + + uint8_t ep_type; /*!< USB endpoint type */ + uint8_t ep_stall; /*!< USB endpoint stall status */ + + uint8_t frame_num; /*!< number of frame */ + uint16_t max_len; /*!< Maximum packet lenth */ + + /* transaction level variables */ + uint8_t *xfer_buf; /*!< transmit buffer */ + uint32_t xfer_len; /*!< transmit buffer length */ + uint32_t xfer_count; /*!< transmit buffer count */ + + uint32_t remain_len; /*!< remain packet lenth */ + + uint32_t dma_addr; /*!< DMA address */ +} usb_transc; + +typedef struct _usb_core_driver usb_dev; + +typedef struct _usb_class_core +{ + uint8_t command; /*!< device class request command */ + uint8_t alter_set; /*!< alternative set */ + + uint8_t (*init) (usb_dev *udev, uint8_t config_index); /*!< initialize handler */ + uint8_t (*deinit) (usb_dev *udev, uint8_t config_index); /*!< de-initialize handler */ + + uint8_t (*req_proc) (usb_dev *udev, usb_req *req); /*!< device request handler */ + + uint8_t (*data_in) (usb_dev *udev, uint8_t ep_num); /*!< device data in handler */ + uint8_t (*data_out) (usb_dev *udev, uint8_t ep_num); /*!< device data out handler */ + + uint8_t (*SOF) (usb_dev *udev); /*!< Start of frame handler */ + + uint8_t (*incomplete_isoc_in) (usb_dev *udev); /*!< Incomplete synchronization IN transfer handler */ + uint8_t (*incomplete_isoc_out) (usb_dev *udev); /*!< Incomplete synchronization OUT transfer handler */ +} usb_class_core; + +typedef struct _usb_perp_dev +{ + uint8_t config; /*!< configuration */ + uint8_t dev_addr; /*!< device address */ + + __IO uint8_t cur_status; /*!< current status */ + __IO uint8_t backup_status; /*!< backup status */ + + usb_transc transc_in[USBFS_MAX_TX_FIFOS]; /*!< endpoint IN transaction */ + usb_transc transc_out[USBFS_MAX_TX_FIFOS]; /*!< endpoint OUT transaction */ + + usb_pm pm; /*!< power management */ + usb_desc desc; /*!< USB descriptors */ + usb_control control; /*!< USB control information */ + + usb_class_core *class_core; /*!< class driver */ +} usb_perp_dev; + +typedef struct _usb_core_driver +{ + usb_core_basic bp; /*!< USB basic parameters */ + usb_core_regs regs; /*!< USB registers */ + usb_perp_dev dev; /*!< USB peripheral device */ +} usb_core_driver; + +/* function declarations */ + +/* initialize USB core registers for device mode */ +usb_status usb_devcore_init (usb_core_driver *udev); + +/* enable the USB device mode interrupts */ +usb_status usb_devint_enable (usb_core_driver *udev); + +/* active the usb transaction */ +usb_status usb_transc_active (usb_core_driver *udev, usb_transc *transc); + +/* deactive the usb transaction */ +usb_status usb_transc_deactivate (usb_core_driver *udev, usb_transc *transc); + +/* configure usb transaction to start IN transfer */ +usb_status usb_transc_inxfer (usb_core_driver *udev, usb_transc *transc); + +/* configure usb transaction to start OUT transfer */ +usb_status usb_transc_outxfer (usb_core_driver *udev, usb_transc *transc); + +/* set the usb transaction STALL status */ +usb_status usb_transc_stall (usb_core_driver *udev, usb_transc *transc); + +/* clear the usb transaction STALL status */ +usb_status usb_transc_clrstall (usb_core_driver *udev, usb_transc *transc); + +/* read device all OUT endpoint interrupt register */ +uint32_t usb_oepintnum_read (usb_core_driver *udev); + +/* read device OUT endpoint interrupt flag register */ +uint32_t usb_oepintr_read (usb_core_driver *udev, uint8_t ep_num); + +/* read device all IN endpoint interrupt register */ +uint32_t usb_iepintnum_read (usb_core_driver *udev); + +/* read device IN endpoint interrupt flag register */ +uint32_t usb_iepintr_read (usb_core_driver *udev, uint8_t ep_num); + +/* config the USB device to be disconnected */ +void usb_dev_disconnect (usb_core_driver *udev); + +/* config the USB device to be connected */ +void usb_dev_connect (usb_core_driver *udev); + +/* set the USB device address */ +void usb_devaddr_set (usb_core_driver *pudev, uint8_t dev_addr); + +/* configures OUT endpoint 0 to receive SETUP packets */ +void usb_ctlep_startout (usb_core_driver *udev); + +/* active remote wakeup signalling */ +void usb_rwkup_active (usb_core_driver *udev); + +/* reset remote wakeup signalling */ +void usb_rwkup_reset (usb_core_driver *udev); + +/* set remote wakeup signalling */ +void usb_rwkup_set (usb_core_driver *udev); + +/* active USB core clock */ +void usb_clock_active (usb_core_driver *udev); + +/* usb device suspend */ +void usb_dev_suspend (usb_core_driver *udev); + +/* stop the device and clean up fifos */ +void usb_dev_stop (usb_core_driver *udev); + +#endif /* __DRV_USB_DEV_H */ + diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_host.h b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_host.h new file mode 100644 index 0000000..e31f3e5 --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_host.h @@ -0,0 +1,175 @@ +/*! + \file drv_usb_host.h + \brief USB host mode low level driver header file + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#ifndef __DRV_USB_HOST_H +#define __DRV_USB_HOST_H + +#include "drv_usb_regs.h" +#include "usb_ch9_std.h" +#include "drv_usb_core.h" + +typedef enum _usb_pipe_status +{ + PIPE_IDLE = 0U, + PIPE_XF, + PIPE_HALTED, + PIPE_NAK, + PIPE_NYET, + PIPE_STALL, + PIPE_TRACERR, + PIPE_BBERR, + PIPE_REQOVR, + PIPE_DTGERR, +} usb_pipe_staus; + +typedef enum _usb_pipe_mode +{ + PIPE_PERIOD = 0U, + PIPE_NON_PERIOD = 1U +} usb_pipe_mode; + +typedef enum _usb_urb_state +{ + URB_IDLE = 0U, + URB_DONE, + URB_NOTREADY, + URB_ERROR, + URB_STALL +} usb_urb_state; + +typedef struct _usb_pipe +{ + uint8_t in_used; + uint8_t dev_addr; + uint32_t dev_speed; + + struct { + uint8_t num; + uint8_t dir; + uint8_t type; + uint16_t mps; + } ep; + + uint8_t ping; + uint32_t DPID; + + uint8_t *xfer_buf; + uint32_t xfer_len; + uint32_t xfer_count; + + uint8_t data_toggle_in; + uint8_t data_toggle_out; + + __IO uint32_t err_count; + __IO usb_pipe_staus pp_status; + __IO usb_urb_state urb_state; +} usb_pipe; + + +typedef struct _usb_host_drv +{ + uint8_t rx_buf[512U]; + __IO uint32_t connect_status; + __IO uint32_t port_enabled; + __IO uint32_t backup_xfercount[USBFS_MAX_TX_FIFOS]; + + usb_pipe pipe[USBFS_MAX_TX_FIFOS]; +} usb_host_drv; + +typedef struct _usb_core_driver +{ + usb_core_basic bp; + + usb_core_regs regs; + + usb_host_drv host; +} usb_core_driver; + +/* initializes USB core for host mode */ +usb_status usb_host_init (usb_core_driver *pudev); + +/* initialize host pipe */ +usb_status usb_pipe_init (usb_core_driver *pudev, uint8_t pipe_num); + +/* prepare host pipe for transferring packets */ +usb_status usb_pipe_xfer (usb_core_driver *pudev, uint8_t pipe_num); + +/* halt host pipe */ +usb_status usb_pipe_halt (usb_core_driver *pudev, uint8_t pipe_num); + +/* configure host pipe to do ping operation */ +usb_status usb_pipe_ping (usb_core_driver *pudev, uint8_t pipe_num); + +/* reset host port */ +uint32_t usb_port_reset (usb_core_driver *pudev); + +/* control the VBUS to power */ +void usb_portvbus_switch (usb_core_driver *pudev, uint8_t state); + +/* stop the USB host and clean up FIFO */ +void usb_host_stop (usb_core_driver *pudev); + +//__STATIC_INLINE uint8_t usb_frame_even (usb_core_driver *pudev) +uint32_t usb_frame_even (usb_core_driver *pudev); +//{ + // return !(pudev->regs.hr->HFINFR & 0x01U); +//} + +//__STATIC_INLINE void usb_phyclock_config (usb_core_driver *pudev, uint8_t clock) +void usb_phyclock_config (usb_core_driver *pudev, uint8_t clock) ; +//{ + //pudev->regs.hr->HCTL &= ~HCTL_CLKSEL; + // pudev->regs.hr->HCTL |= clock; +//} + +uint32_t usb_port_read (usb_core_driver *pudev); +//inline uint32_t usb_port_read (usb_core_driver *pudev) +//{ + // return *pudev->regs.HPCS & ~(HPCS_PE | HPCS_PCD | HPCS_PEDC); +//} + +uint32_t usb_curspeed_get (usb_core_driver *pudev); + +//inline uint32_t usb_curspeed_get (usb_core_driver *pudev) +//{ + // return *pudev->regs.HPCS & HPCS_PS; +//} + +//__STATIC_INLINE uint32_t usb_curframe_get (usb_core_driver *pudev) +uint32_t usb_curframe_get (usb_core_driver *pudev); +//{ + // return (pudev->regs.hr->HFINFR & 0xFFFFU); +//} + +#endif /* __DRV_USB_HOST_H */ diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_hw.h b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_hw.h new file mode 100644 index 0000000..058efa8 --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_hw.h @@ -0,0 +1,62 @@ +/*! + \file drv_usb_hw.h + \brief usb hardware configuration header file + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#ifndef __DRV_USB_HW_H +#define __DRV_USB_HW_H + +#include "usb_conf.h" + +/* configure USB clock */ +void usb_rcu_config (void); + +/* configure USB interrupt */ +void usb_intr_config (void); + +/* initializes delay unit using Timer2 */ +void usb_timer_init (void); + +/* delay in micro seconds */ +void usb_udelay (const uint32_t usec); + +/* delay in milli seconds */ +void usb_mdelay (const uint32_t msec); + +#ifdef USE_HOST_MODE +/* configure USB VBus */ + void usb_vbus_config (void); +/* drive usb VBus */ + void usb_vbus_drive (uint8_t State); +#endif /* USE_HOST_MODE */ + +#endif /* __DRV_USB_HW_H */ diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_regs.h b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_regs.h new file mode 100644 index 0000000..451fd6f --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usb_regs.h @@ -0,0 +1,666 @@ +/*! + \file drv_usb_regs.h + \brief USB cell registers definition and handle macros + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#ifndef __DRV_USB_REGS_H +#define __DRV_USB_REGS_H + +#include "usb_conf.h" + +#define USBHS_REG_BASE 0x40040000L /*!< base address of USBHS registers */ +#define USBFS_REG_BASE 0x50000000L /*!< base address of USBFS registers */ + +#define USBFS_MAX_TX_FIFOS 15 /*!< FIFO number */ + +#define USBFS_MAX_PACKET_SIZE 64U /*!< USBFS max packet size */ +#define USBFS_MAX_CHANNEL_COUNT 8U /*!< USBFS host channel count */ +#define USBFS_MAX_EP_COUNT 4U /*!< USBFS device endpoint count */ +#define USBFS_MAX_FIFO_WORDLEN 320U /*!< USBFS max fifo size in words */ + +#define USBHS_MAX_PACKET_SIZE 512U /*!< USBHS max packet size */ +#define USBHS_MAX_CHANNEL_COUNT 12U /*!< USBHS host channel count */ +#define USBHS_MAX_EP_COUNT 6U /*!< USBHS device endpoint count */ +#define USBHS_MAX_FIFO_WORDLEN 1280U /*!< USBHS max fifo size in words */ + +#define USB_DATA_FIFO_OFFSET 0x1000U /*!< USB data fifo offset */ +#define USB_DATA_FIFO_SIZE 0x1000U /*!< USB data fifo size */ + +typedef enum +{ + USB_CORE_ENUM_HS = 0, /*!< USB core type is HS */ + USB_CORE_ENUM_FS = 1 /*!< USB core type is FS */ +} usb_core_enum; + +enum usb_reg_offset { + USB_REG_OFFSET_CORE = 0x0000U, /*!< global OTG control and status register */ + USB_REG_OFFSET_DEV = 0x0800U, /*!< device mode control and status registers */ + USB_REG_OFFSET_EP = 0x0020U, + USB_REG_OFFSET_EP_IN = 0x0900U, /*!< device IN endpoint 0 control register */ + USB_REG_OFFSET_EP_OUT = 0x0B00U, /*!< device OUT endpoint 0 control register */ + USB_REG_OFFSET_HOST = 0x0400U, /*!< host control register */ + USB_REG_OFFSET_CH = 0x0020U, + USB_REG_OFFSET_PORT = 0x0440U, /*!< host port control and status register */ + USB_REG_OFFSET_CH_INOUT = 0x0500U, /*!< Host channel-x control registers */ + USB_REG_OFFSET_PWRCLKCTL = 0x0E00U, /*!< power and clock register */ +}; + +typedef struct +{ + __IO uint32_t GOTGCS; /*!< USB global OTG control and status register 000h */ + __IO uint32_t GOTGINTF; /*!< USB global OTG interrupt flag register 004h */ + __IO uint32_t GAHBCS; /*!< USB global AHB control and status register 008h */ + __IO uint32_t GUSBCS; /*!< USB global USB control and status register 00Ch */ + __IO uint32_t GRSTCTL; /*!< USB global reset control register 010h */ + __IO uint32_t GINTF; /*!< USB global interrupt flag register 014h */ + __IO uint32_t GINTEN; /*!< USB global interrupt enable register 018h */ + __IO uint32_t GRSTATR; /*!< USB receive status debug read register 01Ch */ + __IO uint32_t GRSTATP; /*!< USB receive status and pop register 020h */ + __IO uint32_t GRFLEN; /*!< USB global receive FIFO length register 024h */ + __IO uint32_t DIEP0TFLEN_HNPTFLEN; /*!< USB device IN endpoint 0/host non-periodic transmit FIFO length register 028h */ + __IO uint32_t HNPTFQSTAT; /*!< USB host non-periodic FIFO/queue status register 02Ch */ + uint32_t Reserved30[2]; /*!< Reserved 030h */ + __IO uint32_t GCCFG; /*!< USB global core configuration register 038h */ + __IO uint32_t CID; /*!< USB core ID register 03Ch */ + uint32_t Reserved40[48]; /*!< Reserved 040h-0FFh */ + __IO uint32_t HPTFLEN; /*!< USB host periodic transmit FIFO length register 100h */ + __IO uint32_t DIEPTFLEN[15]; /*!< USB device IN endpoint transmit FIFO length register 104h */ +} usb_gr; + + +typedef struct +{ + __IO uint32_t HCTL; /*!< USB host control register 400h */ + __IO uint32_t HFT; /*!< USB host frame interval register 404h */ + __IO uint32_t HFINFR; /*!< USB host frame information remaining register 408h */ + uint32_t Reserved40C; /*!< Reserved 40Ch */ + __IO uint32_t HPTFQSTAT; /*!< USB host periodic transmit FIFO/queue status register 410h */ + __IO uint32_t HACHINT; /*!< USB host all channels interrupt register 414h */ + __IO uint32_t HACHINTEN; /*!< USB host all channels interrupt enable register 418h */ +} usb_hr; + +typedef struct +{ + __IO uint32_t HCHCTL; /*!< USB host channel control register 500h */ + __IO uint32_t HCHSTCTL; /*!< Reserved 504h */ + __IO uint32_t HCHINTF; /*!< USB host channel interrupt flag register 508h */ + __IO uint32_t HCHINTEN; /*!< USB host channel interrupt enable register 50Ch */ + __IO uint32_t HCHLEN; /*!< USB host channel transfer length register 510h */ + __IO uint32_t HCHDMAADDR; /*!< USB host channel-x DMA address register 514h*/ + uint32_t Reserved[2]; +} usb_pr; + +typedef struct +{ + __IO uint32_t DCFG; /*!< USB device configuration register 800h */ + __IO uint32_t DCTL; /*!< USB device control register 804h */ + __IO uint32_t DSTAT; /*!< USB device status register 808h */ + uint32_t Reserved0C; /*!< Reserved 80Ch */ + __IO uint32_t DIEPINTEN; /*!< USB device IN endpoint common interrupt enable register 810h */ + __IO uint32_t DOEPINTEN; /*!< USB device OUT endpoint common interrupt enable register 814h */ + __IO uint32_t DAEPINT; /*!< USB device all endpoints interrupt register 818h */ + __IO uint32_t DAEPINTEN; /*!< USB device all endpoints interrupt enable register 81Ch */ + uint32_t Reserved20; /*!< Reserved 820h */ + uint32_t Reserved24; /*!< Reserved 824h */ + __IO uint32_t DVBUSDT; /*!< USB device VBUS discharge time register 828h */ + __IO uint32_t DVBUSPT; /*!< USB device VBUS pulsing time register 82Ch */ + __IO uint32_t DTHRCTL; /*!< dev thr 830h */ + __IO uint32_t DIEPFEINTEN; /*!< USB Device IN endpoint FIFO empty interrupt enable register 834h */ + __IO uint32_t DEP1INT; /*!< USB device endpoint 1 interrupt register 838h */ + __IO uint32_t DEP1INTEN; /*!< USB device endpoint 1 interrupt enable register 83Ch */ + uint32_t Reserved40; /*!< Reserved 840h */ + __IO uint32_t DIEP1INTEN; /*!< USB device IN endpoint-1 interrupt enable register 844h */ + uint32_t Reserved48[15]; /*!< Reserved 848-880h */ + __IO uint32_t DOEP1INTEN; /*!< USB device OUT endpoint-1 interrupt enable register 884h */ +} usb_dr; + +typedef struct +{ + __IO uint32_t DIEPCTL; /*!< USB device IN endpoint control register 900h + (EpNum * 20h) + 00h */ + uint32_t Reserved04; /*!< Reserved 900h + (EpNum * 20h) + 04h */ + __IO uint32_t DIEPINTF; /*!< USB device IN endpoint interrupt flag register 900h + (EpNum * 20h) + 08h */ + uint32_t Reserved0C; /*!< Reserved 900h + (EpNum * 20h) + 0Ch */ + __IO uint32_t DIEPLEN; /*!< USB device IN endpoint transfer length register 900h + (EpNum * 20h) + 10h */ + __IO uint32_t DIEPDMAADDR; /*!< Device IN endpoint-x DMA address register 900h + (EpNum * 20h) + 14h */ + __IO uint32_t DIEPTFSTAT; /*!< USB device IN endpoint transmit FIFO status register 900h + (EpNum * 20h) + 18h */ +} usb_erin; + +typedef struct +{ + __IO uint32_t DOEPCTL; /*!< USB device IN endpoint control register B00h + (EpNum * 20h) + 00h */ + uint32_t Reserved04; /*!< Reserved B00h + (EpNum * 20h) + 04h */ + __IO uint32_t DOEPINTF; /*!< USB device IN endpoint interrupt flag register B00h + (EpNum * 20h) + 08h */ + uint32_t Reserved0C; /*!< Reserved B00h + (EpNum * 20h) + 0Ch */ + __IO uint32_t DOEPLEN; /*!< USB device IN endpoint transfer length register B00h + (EpNum * 20h) + 10h */ + __IO uint32_t DOEPDMAADDR; /*!< Device OUT endpoint-x DMA address register B00h + (EpNum * 20h) + 0Ch */ +} usb_erout; + +typedef struct _usb_regs +{ + usb_gr *gr; /*!< USBFS global registers */ + usb_dr *dr; /*!< Device control and status registers */ + usb_hr *hr; /*!< Host control and status registers */ + usb_erin *er_in[6]; /*!< USB device IN endpoint register */ + usb_erout *er_out[6]; /*!< USB device OUT endpoint register */ + usb_pr *pr[15]; /*!< USB Host channel-x control register */ + + __IO uint32_t *HPCS; /*!< USB host port control and status register */ + __IO uint32_t *DFIFO[USBFS_MAX_TX_FIFOS]; + __IO uint32_t *PWRCLKCTL; /*!< USB power and clock control register */ +} usb_core_regs; + +/* global OTG control and status register bits definitions */ +#define GOTGCS_BSV BIT(19) /*!< B-Session Valid */ +#define GOTGCS_ASV BIT(18) /*!< A-session valid */ +#define GOTGCS_DI BIT(17) /*!< debounce interval */ +#define GOTGCS_CIDPS BIT(16) /*!< id pin status */ +#define GOTGCS_DHNPEN BIT(11) /*!< device HNP enable */ +#define GOTGCS_HHNPEN BIT(10) /*!< host HNP enable */ +#define GOTGCS_HNPREQ BIT(9) /*!< HNP request */ +#define GOTGCS_HNPS BIT(8) /*!< HNP successes */ +#define GOTGCS_SRPREQ BIT(1) /*!< SRP request */ +#define GOTGCS_SRPS BIT(0) /*!< SRP successes */ + +/* global OTG interrupt flag register bits definitions */ +#define GOTGINTF_DF BIT(19) /*!< debounce finish */ +#define GOTGINTF_ADTO BIT(18) /*!< A-device timeout */ +#define GOTGINTF_HNPDET BIT(17) /*!< host negotiation request detected */ +#define GOTGINTF_HNPEND BIT(9) /*!< HNP end */ +#define GOTGINTF_SRPEND BIT(8) /*!< SRP end */ +#define GOTGINTF_SESEND BIT(2) /*!< session end */ + +/* global AHB control and status register bits definitions */ +#define GAHBCS_PTXFTH BIT(8) /*!< periodic Tx FIFO threshold */ +#define GAHBCS_TXFTH BIT(7) /*!< tx FIFO threshold */ +#define GAHBCS_DMAEN BIT(5) /*!< DMA function Enable */ +#define GAHBCS_BURST BITS(1, 4) /*!< the AHB burst type used by DMA */ +#define GAHBCS_GINTEN BIT(0) /*!< global interrupt enable */ + +/* global USB control and status register bits definitions */ +#define GUSBCS_FDM BIT(30) /*!< force device mode */ +#define GUSBCS_FHM BIT(29) /*!< force host mode */ +#define GUSBCS_ULPIEOI BIT(21) /*!< ULPI external over-current indicator */ +#define GUSBCS_ULPIEVD BIT(20) /*!< ULPI external VBUS driver */ +#define GUSBCS_UTT BITS(10, 13) /*!< USB turnaround time */ +#define GUSBCS_HNPCEN BIT(9) /*!< HNP capability enable */ +#define GUSBCS_SRPCEN BIT(8) /*!< SRP capability enable */ +#define GUSBCS_EMBPHY BIT(6) /*!< embedded PHY selected */ +#define GUSBCS_TOC BITS(0, 2) /*!< timeout calibration */ + +/* global reset control register bits definitions */ +#define GRSTCTL_DMAIDL BIT(31) /*!< DMA idle state */ +#define GRSTCTL_DMABSY BIT(30) /*!< DMA busy */ +#define GRSTCTL_TXFNUM BITS(6, 10) /*!< tx FIFO number */ +#define GRSTCTL_TXFF BIT(5) /*!< tx FIFO flush */ +#define GRSTCTL_RXFF BIT(4) /*!< rx FIFO flush */ +#define GRSTCTL_HFCRST BIT(2) /*!< host frame counter reset */ +#define GRSTCTL_HCSRST BIT(1) /*!< HCLK soft reset */ +#define GRSTCTL_CSRST BIT(0) /*!< core soft reset */ + +/* global interrupt flag register bits definitions */ +#define GINTF_WKUPIF BIT(31) /*!< wakeup interrupt flag */ +#define GINTF_SESIF BIT(30) /*!< session interrupt flag */ +#define GINTF_DISCIF BIT(29) /*!< disconnect interrupt flag */ +#define GINTF_IDPSC BIT(28) /*!< id pin status change */ +#define GINTF_PTXFEIF BIT(26) /*!< periodic tx FIFO empty interrupt flag */ +#define GINTF_HCIF BIT(25) /*!< host channels interrupt flag */ +#define GINTF_HPIF BIT(24) /*!< host port interrupt flag */ +#define GINTF_PXNCIF BIT(21) /*!< periodic transfer not complete interrupt flag */ +#define GINTF_ISOONCIF BIT(21) /*!< isochronous OUT transfer not complete interrupt flag */ +#define GINTF_ISOINCIF BIT(20) /*!< isochronous IN transfer not complete interrupt flag */ +#define GINTF_OEPIF BIT(19) /*!< OUT endpoint interrupt flag */ +#define GINTF_IEPIF BIT(18) /*!< IN endpoint interrupt flag */ +#define GINTF_EOPFIF BIT(15) /*!< end of periodic frame interrupt flag */ +#define GINTF_ISOOPDIF BIT(14) /*!< isochronous OUT packet dropped interrupt flag */ +#define GINTF_ENUMFIF BIT(13) /*!< enumeration finished */ +#define GINTF_RST BIT(12) /*!< USB reset */ +#define GINTF_SP BIT(11) /*!< USB suspend */ +#define GINTF_ESP BIT(10) /*!< early suspend */ +#define GINTF_GONAK BIT(7) /*!< global OUT NAK effective */ +#define GINTF_GNPINAK BIT(6) /*!< global IN non-periodic NAK effective */ +#define GINTF_NPTXFEIF BIT(5) /*!< non-periodic tx FIFO empty interrupt flag */ +#define GINTF_RXFNEIF BIT(4) /*!< rx FIFO non-empty interrupt flag */ +#define GINTF_SOF BIT(3) /*!< start of frame */ +#define GINTF_OTGIF BIT(2) /*!< OTG interrupt flag */ +#define GINTF_MFIF BIT(1) /*!< mode fault interrupt flag */ +#define GINTF_COPM BIT(0) /*!< current operation mode */ + +/* global interrupt enable register bits definitions */ +#define GINTEN_WKUPIE BIT(31) /*!< wakeup interrupt enable */ +#define GINTEN_SESIE BIT(30) /*!< session interrupt enable */ +#define GINTEN_DISCIE BIT(29) /*!< disconnect interrupt enable */ +#define GINTEN_IDPSCIE BIT(28) /*!< id pin status change interrupt enable */ +#define GINTEN_PTXFEIE BIT(26) /*!< periodic tx FIFO empty interrupt enable */ +#define GINTEN_HCIE BIT(25) /*!< host channels interrupt enable */ +#define GINTEN_HPIE BIT(24) /*!< host port interrupt enable */ +#define GINTEN_IPXIE BIT(21) /*!< periodic transfer not complete interrupt enable */ +#define GINTEN_ISOONCIE BIT(21) /*!< isochronous OUT transfer not complete interrupt enable */ +#define GINTEN_ISOINCIE BIT(20) /*!< isochronous IN transfer not complete interrupt enable */ +#define GINTEN_OEPIE BIT(19) /*!< OUT endpoints interrupt enable */ +#define GINTEN_IEPIE BIT(18) /*!< IN endpoints interrupt enable */ +#define GINTEN_EOPFIE BIT(15) /*!< end of periodic frame interrupt enable */ +#define GINTEN_ISOOPDIE BIT(14) /*!< isochronous OUT packet dropped interrupt enable */ +#define GINTEN_ENUMFIE BIT(13) /*!< enumeration finish enable */ +#define GINTEN_RSTIE BIT(12) /*!< USB reset interrupt enable */ +#define GINTEN_SPIE BIT(11) /*!< USB suspend interrupt enable */ +#define GINTEN_ESPIE BIT(10) /*!< early suspend interrupt enable */ +#define GINTEN_GONAKIE BIT(7) /*!< global OUT NAK effective interrupt enable */ +#define GINTEN_GNPINAKIE BIT(6) /*!< global non-periodic IN NAK effective interrupt enable */ +#define GINTEN_NPTXFEIE BIT(5) /*!< non-periodic Tx FIFO empty interrupt enable */ +#define GINTEN_RXFNEIE BIT(4) /*!< receive FIFO non-empty interrupt enable */ +#define GINTEN_SOFIE BIT(3) /*!< start of frame interrupt enable */ +#define GINTEN_OTGIE BIT(2) /*!< OTG interrupt enable */ +#define GINTEN_MFIE BIT(1) /*!< mode fault interrupt enable */ + +/* global receive status read and pop register bits definitions */ +#define GRSTATRP_RPCKST BITS(17, 20) /*!< received packet status */ +#define GRSTATRP_DPID BITS(15, 16) /*!< data PID */ +#define GRSTATRP_BCOUNT BITS(4, 14) /*!< byte count */ +#define GRSTATRP_CNUM BITS(0, 3) /*!< channel number */ +#define GRSTATRP_EPNUM BITS(0, 3) /*!< endpoint number */ + +/* global receive FIFO length register bits definitions */ +#define GRFLEN_RXFD BITS(0, 15) /*!< rx FIFO depth */ + +/* host non-periodic transmit FIFO length register bits definitions */ +#define HNPTFLEN_HNPTXFD BITS(16, 31) /*!< non-periodic Tx FIFO depth */ +#define HNPTFLEN_HNPTXRSAR BITS(0, 15) /*!< non-periodic Tx RAM start address */ + +/** + * @brief USB IN endpoint 0 transmit FIFO length register bits definitions + */ +#define DIEP0TFLEN_IEP0TXFD BITS(16, 31) /*!< IN Endpoint 0 Tx FIFO depth */ +#define DIEP0TFLEN_IEP0TXRSAR BITS(0, 15) /*!< IN Endpoint 0 TX RAM start address */ + +/* host non-periodic transmit FIFO/queue status register bits definitions */ +#define HNPTFQSTAT_NPTXRQTOP BITS(24, 30) /*!< top entry of the non-periodic Tx request queue */ +#define HNPTFQSTAT_NPTXRQS BITS(16, 23) /*!< non-periodic Tx request queue space */ +#define HNPTFQSTAT_NPTXFS BITS(0, 15) /*!< non-periodic Tx FIFO space */ +#define HNPTFQSTAT_CNUM BITS(27, 30) /*!< channel number*/ +#define HNPTFQSTAT_EPNUM BITS(27, 30) /*!< endpoint number */ +#define HNPTFQSTAT_TYPE BITS(25, 26) /*!< token type */ +#define HNPTFQSTAT_TMF BIT(24) /*!< terminate flag */ + +/* global core configuration register bits definitions */ +#define GCCFG_VBUSIG BIT(21) /*!< vbus ignored */ +#define GCCFG_SOFOEN BIT(20) /*!< SOF output enable */ +#define GCCFG_VBUSBCEN BIT(19) /*!< the VBUS B-device comparer enable */ +#define GCCFG_VBUSACEN BIT(18) /*!< the VBUS A-device comparer enable */ +#define GCCFG_PWRON BIT(16) /*!< power on */ + +/* core ID register bits definitions */ +#define CID_CID BITS(0, 31) /*!< core ID */ + +/* host periodic transmit FIFO length register bits definitions */ +#define HPTFLEN_HPTXFD BITS(16, 31) /*!< host periodic Tx FIFO depth */ +#define HPTFLEN_HPTXFSAR BITS(0, 15) /*!< host periodic Tx RAM start address */ + +/* device IN endpoint transmit FIFO length register bits definitions */ +#define DIEPTFLEN_IEPTXFD BITS(16, 31) /*!< IN endpoint Tx FIFO x depth */ +#define DIEPTFLEN_IEPTXRSAR BITS(0, 15) /*!< IN endpoint FIFOx Tx x RAM start address */ + +/* host control register bits definitions */ +#define HCTL_SPDFSLS BIT(2) /*!< speed limited to FS and LS */ +#define HCTL_CLKSEL BITS(0, 1) /*!< clock select for USB clock */ + +/* host frame interval register bits definitions */ +#define HFT_FRI BITS(0, 15) /*!< frame interval */ + +/* host frame information remaining register bits definitions */ +#define HFINFR_FRT BITS(16, 31) /*!< frame remaining time */ +#define HFINFR_FRNUM BITS(0, 15) /*!< frame number */ + +/* host periodic transmit FIFO/queue status register bits definitions */ +#define HPTFQSTAT_PTXREQT BITS(24, 31) /*!< top entry of the periodic Tx request queue */ +#define HPTFQSTAT_PTXREQS BITS(16, 23) /*!< periodic Tx request queue space */ +#define HPTFQSTAT_PTXFS BITS(0, 15) /*!< periodic Tx FIFO space */ +#define HPTFQSTAT_OEFRM BIT(31) /*!< odd/eveb frame */ +#define HPTFQSTAT_CNUM BITS(27, 30) /*!< channel number */ +#define HPTFQSTAT_EPNUM BITS(27, 30) /*!< endpoint number */ +#define HPTFQSTAT_TYPE BITS(25, 26) /*!< token type */ +#define HPTFQSTAT_TMF BIT(24) /*!< terminate flag */ + + +#define TFQSTAT_TXFS BITS(0, 15) +#define TFQSTAT_CNUM BITS(27, 30) + +/* host all channels interrupt register bits definitions */ +#define HACHINT_HACHINT BITS(0, 11) /*!< host all channel interrupts */ + +/* host all channels interrupt enable register bits definitions */ +#define HACHINTEN_CINTEN BITS(0, 11) /*!< channel interrupt enable */ + +/* host port control and status register bits definitions */ +#define HPCS_PS BITS(17, 18) /*!< port speed */ +#define HPCS_PP BIT(12) /*!< port power */ +#define HPCS_PLST BITS(10, 11) /*!< port line status */ +#define HPCS_PRST BIT(8) /*!< port reset */ +#define HPCS_PSP BIT(7) /*!< port suspend */ +#define HPCS_PREM BIT(6) /*!< port resume */ +#define HPCS_PEDC BIT(3) /*!< port enable/disable change */ +#define HPCS_PE BIT(2) /*!< port enable */ +#define HPCS_PCD BIT(1) /*!< port connect detected */ +#define HPCS_PCST BIT(0) /*!< port connect status */ + +/* host channel-x control register bits definitions */ +#define HCHCTL_CEN BIT(31) /*!< channel enable */ +#define HCHCTL_CDIS BIT(30) /*!< channel disable */ +#define HCHCTL_ODDFRM BIT(29) /*!< odd frame */ +#define HCHCTL_DAR BITS(22, 28) /*!< device address */ +#define HCHCTL_MPC BITS(20, 21) /*!< multiple packet count */ +#define HCHCTL_EPTYPE BITS(18, 19) /*!< endpoint type */ +#define HCHCTL_LSD BIT(17) /*!< low-speed device */ +#define HCHCTL_EPDIR BIT(15) /*!< endpoint direction */ +#define HCHCTL_EPNUM BITS(11, 14) /*!< endpoint number */ +#define HCHCTL_MPL BITS(0, 10) /*!< maximum packet length */ + +/* host channel-x split transaction register bits definitions */ +#define HCHSTCTL_SPLEN BIT(31) /*!< enable high-speed split transaction */ +#define HCHSTCTL_CSPLT BIT(16) /*!< complete-split enable */ +#define HCHSTCTL_ISOPCE BITS(14, 15) /*!< isochronous OUT payload continuation encoding */ +#define HCHSTCTL_HADDR BITS(7, 13) /*!< HUB address */ +#define HCHSTCTL_PADDR BITS(0, 6) /*!< port address */ + +/* host channel-x interrupt flag register bits definitions */ +#define HCHINTF_DTER BIT(10) /*!< data toggle error */ +#define HCHINTF_REQOVR BIT(9) /*!< request queue overrun */ +#define HCHINTF_BBER BIT(8) /*!< babble error */ +#define HCHINTF_USBER BIT(7) /*!< USB bus Error */ +#define HCHINTF_NYET BIT(6) /*!< NYET */ +#define HCHINTF_ACK BIT(5) /*!< ACK */ +#define HCHINTF_NAK BIT(4) /*!< NAK */ +#define HCHINTF_STALL BIT(3) /*!< STALL */ +#define HCHINTF_DMAER BIT(2) /*!< DMA error */ +#define HCHINTF_CH BIT(1) /*!< channel halted */ +#define HCHINTF_TF BIT(0) /*!< transfer finished */ + +/* host channel-x interrupt enable register bits definitions */ +#define HCHINTEN_DTERIE BIT(10) /*!< data toggle error interrupt enable */ +#define HCHINTEN_REQOVRIE BIT(9) /*!< request queue overrun interrupt enable */ +#define HCHINTEN_BBERIE BIT(8) /*!< babble error interrupt enable */ +#define HCHINTEN_USBERIE BIT(7) /*!< USB bus error interrupt enable */ +#define HCHINTEN_NYETIE BIT(6) /*!< NYET interrupt enable */ +#define HCHINTEN_ACKIE BIT(5) /*!< ACK interrupt enable */ +#define HCHINTEN_NAKIE BIT(4) /*!< NAK interrupt enable */ +#define HCHINTEN_STALLIE BIT(3) /*!< STALL interrupt enable */ +#define HCHINTEN_DMAERIE BIT(2) /*!< DMA error interrupt enable */ +#define HCHINTEN_CHIE BIT(1) /*!< channel halted interrupt enable */ +#define HCHINTEN_TFIE BIT(0) /*!< transfer finished interrupt enable */ + +/* host channel-x transfer length register bits definitions */ +#define HCHLEN_PING BIT(31) /*!< PING token request */ +#define HCHLEN_DPID BITS(29, 30) /*!< data PID */ +#define HCHLEN_PCNT BITS(19, 28) /*!< packet count */ +#define HCHLEN_TLEN BITS(0, 18) /*!< transfer length */ + +/* host channel-x DMA address register bits definitions */ +#define HCHDMAADDR_DMAADDR BITS(0, 31) /*!< DMA address */ + + +#define PORT_SPEED(x) (((uint32_t)(x) << 17) & HPCS_PS) /*!< Port speed */ + +#define PORT_SPEED_HIGH PORT_SPEED(0) /*!< high speed */ +#define PORT_SPEED_FULL PORT_SPEED(1) /*!< full speed */ +#define PORT_SPEED_LOW PORT_SPEED(2) /*!< low speed */ + +#define PIPE_CTL_DAR(x) (((uint32_t)(x) << 22) & HCHCTL_DAR) /*!< device address */ +#define PIPE_CTL_EPTYPE(x) (((uint32_t)(x) << 18) & HCHCTL_EPTYPE) /*!< endpoint type */ +#define PIPE_CTL_EPNUM(x) (((uint32_t)(x) << 11) & HCHCTL_EPNUM) /*!< endpoint number */ +#define PIPE_CTL_EPDIR(x) (((uint32_t)(x) << 15) & HCHCTL_EPDIR) /*!< endpoint direction */ +#define PIPE_CTL_EPMPL(x) (((uint32_t)(x) << 0) & HCHCTL_MPL) /*!< maximum packet length */ +#define PIPE_CTL_LSD(x) (((uint32_t)(x) << 17) & HCHCTL_LSD) /*!< low-Speed device */ + +#define PIPE_XFER_PCNT(x) (((uint32_t)(x) << 19) & HCHLEN_PCNT) /*!< packet count */ +#define PIPE_XFER_DPID(x) (((uint32_t)(x) << 29) & HCHLEN_DPID) /*!< data PID */ + +#define PIPE_DPID_DATA0 PIPE_XFER_DPID(0) /*!< DATA0 */ +#define PIPE_DPID_DATA1 PIPE_XFER_DPID(2) /*!< DATA1 */ +#define PIPE_DPID_DATA2 PIPE_XFER_DPID(1) /*!< DATA2 */ +#define PIPE_DPID_SETUP PIPE_XFER_DPID(3) /*!< MDATA (non-control)/SETUP (control) */ + +extern const uint32_t PIPE_DPID[]; + +/* device configuration registers bits definitions */ +#define DCFG_EOPFT BITS(11, 12) /*!< end of periodic frame time */ +#define DCFG_DAR BITS(4, 10) /*!< device address */ +#define DCFG_NZLSOH BIT(2) /*!< non-zero-length status OUT handshake */ +#define DCFG_DS BITS(0, 1) /*!< device speed */ + +/* device control registers bits definitions */ +#define DCTL_POIF BIT(11) /*!< power-on initialization finished */ +#define DCTL_CGONAK BIT(10) /*!< clear global OUT NAK */ +#define DCTL_SGONAK BIT(9) /*!< set global OUT NAK */ +#define DCTL_CGINAK BIT(8) /*!< clear global IN NAK */ +#define DCTL_SGINAK BIT(7) /*!< set global IN NAK */ +#define DCTL_GONS BIT(3) /*!< global OUT NAK status */ +#define DCTL_GINS BIT(2) /*!< global IN NAK status */ +#define DCTL_SD BIT(1) /*!< soft disconnect */ +#define DCTL_RWKUP BIT(0) /*!< remote wakeup */ + +/* device status registers bits definitions */ +#define DSTAT_FNRSOF BITS(8, 21) /*!< the frame number of the received SOF. */ +#define DSTAT_ES BITS(1, 2) /*!< enumerated speed */ +#define DSTAT_SPST BIT(0) /*!< suspend status */ + +/* device IN endpoint common interrupt enable registers bits definitions */ +#define DIEPINTEN_NAKEN BIT(13) /*!< NAK handshake sent by USBHS interrupt enable bit */ +#define DIEPINTEN_TXFEEN BIT(7) /*!< transmit FIFO empty interrupt enable bit */ +#define DIEPINTEN_IEPNEEN BIT(6) /*!< IN endpoint NAK effective interrupt enable bit */ +#define DIEPINTEN_EPTXFUDEN BIT(4) /*!< endpoint Tx FIFO underrun interrupt enable bit */ +#define DIEPINTEN_CITOEN BIT(3) /*!< control In Timeout interrupt enable bit */ +#define DIEPINTEN_EPDISEN BIT(1) /*!< endpoint disabled interrupt enable bit */ +#define DIEPINTEN_TFEN BIT(0) /*!< transfer finished interrupt enable bit */ + +/* device OUT endpoint common interrupt enable registers bits definitions */ +#define DOEPINTEN_NYETEN BIT(14) /*!< NYET handshake is sent interrupt enable bit */ +#define DOEPINTEN_BTBSTPEN BIT(6) /*!< back-to-back SETUP packets interrupt enable bit */ +#define DOEPINTEN_EPRXFOVREN BIT(4) /*!< endpoint Rx FIFO overrun interrupt enable bit */ +#define DOEPINTEN_STPFEN BIT(3) /*!< SETUP phase finished interrupt enable bit */ +#define DOEPINTEN_EPDISEN BIT(1) /*!< endpoint disabled interrupt enable bit */ +#define DOEPINTEN_TFEN BIT(0) /*!< transfer finished interrupt enable bit */ + +/* device all endpoints interrupt registers bits definitions */ +#define DAEPINT_OEPITB BITS(16, 21) /*!< device all OUT endpoint interrupt bits */ +#define DAEPINT_IEPITB BITS(0, 5) /*!< device all IN endpoint interrupt bits */ + +/* device all endpoints interrupt enable registers bits definitions */ +#define DAEPINTEN_OEPIE BITS(16, 21) /*!< OUT endpoint interrupt enable */ +#define DAEPINTEN_IEPIE BITS(0, 3) /*!< IN endpoint interrupt enable */ + +/* device Vbus discharge time registers bits definitions */ +#define DVBUSDT_DVBUSDT BITS(0, 15) /*!< device VBUS discharge time */ + +/* device Vbus pulsing time registers bits definitions */ +#define DVBUSPT_DVBUSPT BITS(0, 11) /*!< device VBUS pulsing time */ + +/* device IN endpoint FIFO empty interrupt enable register bits definitions */ +#define DIEPFEINTEN_IEPTXFEIE BITS(0, 5) /*!< IN endpoint Tx FIFO empty interrupt enable bits */ + +/* device endpoint 0 control register bits definitions */ +#define DEP0CTL_EPEN BIT(31) /*!< endpoint enable */ +#define DEP0CTL_EPD BIT(30) /*!< endpoint disable */ +#define DEP0CTL_SNAK BIT(27) /*!< set NAK */ +#define DEP0CTL_CNAK BIT(26) /*!< clear NAK */ +#define DIEP0CTL_TXFNUM BITS(22, 25) /*!< tx FIFO number */ +#define DEP0CTL_STALL BIT(21) /*!< STALL handshake */ +#define DOEP0CTL_SNOOP BIT(20) /*!< snoop mode */ +#define DEP0CTL_EPTYPE BITS(18, 19) /*!< endpoint type */ +#define DEP0CTL_NAKS BIT(17) /*!< NAK status */ +#define DEP0CTL_EPACT BIT(15) /*!< endpoint active */ +#define DEP0CTL_MPL BITS(0, 1) /*!< maximum packet length */ + +/* device endpoint x control register bits definitions */ +#define DEPCTL_EPEN BIT(31) /*!< endpoint enable */ +#define DEPCTL_EPD BIT(30) /*!< endpoint disable */ +#define DEPCTL_SODDFRM BIT(29) /*!< set odd frame */ +#define DEPCTL_SD1PID BIT(29) /*!< set DATA1 PID */ +#define DEPCTL_SEVNFRM BIT(28) /*!< set even frame */ +#define DEPCTL_SD0PID BIT(28) /*!< set DATA0 PID */ +#define DEPCTL_SNAK BIT(27) /*!< set NAK */ +#define DEPCTL_CNAK BIT(26) /*!< clear NAK */ +#define DIEPCTL_TXFNUM BITS(22, 25) /*!< tx FIFO number */ +#define DEPCTL_STALL BIT(21) /*!< STALL handshake */ +#define DOEPCTL_SNOOP BIT(20) /*!< snoop mode */ +#define DEPCTL_EPTYPE BITS(18, 19) /*!< endpoint type */ +#define DEPCTL_NAKS BIT(17) /*!< NAK status */ +#define DEPCTL_EOFRM BIT(16) /*!< even/odd frame */ +#define DEPCTL_DPID BIT(16) /*!< endpoint data PID */ +#define DEPCTL_EPACT BIT(15) /*!< endpoint active */ +#define DEPCTL_MPL BITS(0, 10) /*!< maximum packet length */ + +/* device IN endpoint-x interrupt flag register bits definitions */ +#define DIEPINTF_NAK BIT(13) /*!< NAK handshake sent by USBHS */ +#define DIEPINTF_TXFE BIT(7) /*!< transmit FIFO empty */ +#define DIEPINTF_IEPNE BIT(6) /*!< IN endpoint NAK effective */ +#define DIEPINTF_EPTXFUD BIT(4) /*!< endpoint Tx FIFO underrun */ +#define DIEPINTF_CITO BIT(3) /*!< control In Timeout interrupt */ +#define DIEPINTF_EPDIS BIT(1) /*!< endpoint disabled */ +#define DIEPINTF_TF BIT(0) /*!< transfer finished */ + +/* device OUT endpoint-x interrupt flag register bits definitions */ +#define DOEPINTF_NYET BIT(14) /*!< NYET handshake is sent */ +#define DOEPINTF_BTBSTP BIT(6) /*!< back-to-back SETUP packets */ +#define DOEPINTF_EPRXFOVR BIT(4) /*!< endpoint Rx FIFO overrun */ +#define DOEPINTF_STPF BIT(3) /*!< SETUP phase finished */ +#define DOEPINTF_EPDIS BIT(1) /*!< endpoint disabled */ +#define DOEPINTF_TF BIT(0) /*!< transfer finished */ + +/* device IN endpoint 0 transfer length register bits definitions */ +#define DIEP0LEN_PCNT BITS(19, 20) /*!< packet count */ +#define DIEP0LEN_TLEN BITS(0, 6) /*!< transfer length */ + +/* device OUT endpoint 0 transfer length register bits definitions */ +#define DOEP0LEN_STPCNT BITS(29, 30) /*!< SETUP packet count */ +#define DOEP0LEN_PCNT BIT(19) /*!< packet count */ +#define DOEP0LEN_TLEN BITS(0, 6) /*!< transfer length */ + +/* device OUT endpoint-x transfer length register bits definitions */ +#define DOEPLEN_RXDPID BITS(29, 30) /*!< received data PID */ +#define DOEPLEN_STPCNT BITS(29, 30) /*!< SETUP packet count */ +#define DIEPLEN_MCNT BITS(29, 30) /*!< multi count */ +#define DEPLEN_PCNT BITS(19, 28) /*!< packet count */ +#define DEPLEN_TLEN BITS(0, 18) /*!< transfer length */ + +/* device IN endpoint-x DMA address register bits definitions */ +#define DIEPDMAADDR_DMAADDR BITS(0, 31) /*!< DMA address */ + +/* device OUT endpoint-x DMA address register bits definitions */ +#define DOEPDMAADDR_DMAADDR BITS(0, 31) /*!< DMA address */ + +/* device IN endpoint-x transmit FIFO status register bits definitions */ +#define DIEPTFSTAT_IEPTFS BITS(0, 15) /*!< IN endpoint Tx FIFO space remaining */ + +/* USB power and clock registers bits definition */ +#define PWRCLKCTL_SHCLK BIT(1) /*!< stop HCLK */ +#define PWRCLKCTL_SUCLK BIT(0) /*!< stop the USB clock */ + +#define RSTAT_GOUT_NAK 1U /* global OUT NAK (triggers an interrupt) */ +#define RSTAT_DATA_UPDT 2U /* OUT data packet received */ +#define RSTAT_XFER_COMP 3U /* OUT transfer completed (triggers an interrupt) */ +#define RSTAT_SETUP_COMP 4U /* SETUP transaction completed (triggers an interrupt) */ +#define RSTAT_SETUP_UPDT 6U /* SETUP data packet received */ + +#define DSTAT_EM_HS_PHY_30MHZ_60MHZ 0U /* USB enumerate speed use high-speed PHY clock in 30MHz or 60MHz */ +#define DSTAT_EM_FS_PHY_30MHZ_60MHZ 1U /* USB enumerate speed use full-speed PHY clock in 30MHz or 60MHz */ +#define DSTAT_EM_LS_PHY_6MHZ 2U /* USB enumerate speed use low-speed PHY clock in 6MHz */ +#define DSTAT_EM_FS_PHY_48MHZ 3U /* USB enumerate speed use full-speed PHY clock in 48MHz */ + +#define DPID_DATA0 0U /* device endpoint data PID is DATA0 */ +#define DPID_DATA1 2U /* device endpoint data PID is DATA1 */ +#define DPID_DATA2 1U /* device endpoint data PID is DATA2 */ +#define DPID_MDATA 3U /* device endpoint data PID is MDATA */ + +#define GAHBCS_DMAINCR(regval) (GAHBCS_BURST & ((regval) << 1U)) /*!< AHB burst type used by DMA*/ + +#define DMA_INCR0 GAHBCS_DMAINCR(0U) /*!< single burst type used by DMA*/ +#define DMA_INCR1 GAHBCS_DMAINCR(1U) /*!< 4-beat incrementing burst type used by DMA*/ +#define DMA_INCR4 GAHBCS_DMAINCR(3U) /*!< 8-beat incrementing burst type used by DMA*/ +#define DMA_INCR8 GAHBCS_DMAINCR(5U) /*!< 16-beat incrementing burst type used by DMA*/ +#define DMA_INCR16 GAHBCS_DMAINCR(7U) /*!< 32-beat incrementing burst type used by DMA*/ + +#define DCFG_PFRI(regval) (DCFG_EOPFT & ((regval) << 11U)) /*!< end of periodic frame time configuration */ + +#define FRAME_INTERVAL_80 DCFG_PFRI(0U) /*!< 80% of the frame time */ +#define FRAME_INTERVAL_85 DCFG_PFRI(1U) /*!< 85% of the frame time */ +#define FRAME_INTERVAL_90 DCFG_PFRI(2U) /*!< 90% of the frame time */ +#define FRAME_INTERVAL_95 DCFG_PFRI(3U) /*!< 95% of the frame time */ + +#define DCFG_DEVSPEED(regval) (DCFG_DS & ((regval) << 0U)) /*!< device speed configuration */ + +#define USB_SPEED_EXP_HIGH DCFG_DEVSPEED(0U) /*!< device external PHY high speed */ +#define USB_SPEED_EXP_FULL DCFG_DEVSPEED(1U) /*!< device external PHY full speed */ +#define USB_SPEED_INP_FULL DCFG_DEVSPEED(3U) /*!< device internal PHY full speed */ + +#define DEP0_MPL(regval) (DEP0CTL_MPL & ((regval) << 0U)) /*!< maximum packet length configuration */ + +#define EP0MPL_64 DEP0_MPL(0U) /*!< maximum packet length 64 bytes */ +#define EP0MPL_32 DEP0_MPL(1U) /*!< maximum packet length 32 bytes */ +#define EP0MPL_16 DEP0_MPL(2U) /*!< maximum packet length 16 bytes */ +#define EP0MPL_8 DEP0_MPL(3U) /*!< maximum packet length 8 bytes */ + +#define DOEP0_TLEN(regval) (DOEP0LEN_TLEN & ((regval) << 0)) /*!< Transfer length */ +#define DOEP0_PCNT(regval) (DOEP0LEN_PCNT & ((regval) << 19)) /*!< Packet count */ +#define DOEP0_STPCNT(regval) (DOEP0LEN_STPCNT & ((regval) << 29)) /*!< SETUP packet count */ + +#define USB_ULPI_PHY 1 /*!< ULPI interface external PHY */ +#define USB_EMBEDDED_PHY 2 /*!< Embedded PHY */ + +#define GRXSTS_PKTSTS_IN 2 +#define GRXSTS_PKTSTS_IN_XFER_COMP 3 +#define GRXSTS_PKTSTS_DATA_TOGGLE_ERR 5 +#define GRXSTS_PKTSTS_CH_HALTED 7 + +#define DEVICE_MODE 0 /*!< device mode */ +#define HOST_MODE 1 /*!< host mode */ +#define OTG_MODE 2 /*!< OTG mode */ + +#define HCTL_30_60MHZ 0 /*!< USB clock 30-60MHZ */ +#define HCTL_48MHZ 1 /*!< USB clock 48MHZ */ +#define HCTL_6MHZ 2 /*!< USB clock 6MHZ */ + +enum USB_SPEED { + USB_SPEED_UNKNOWN = 0, /*!< USB speed unknown */ + USB_SPEED_LOW, /*!< USB speed low */ + USB_SPEED_FULL, /*!< USB speed full */ + USB_SPEED_HIGH /*!< USB speed high */ +}; + +#define EP0_OUT ((uint8_t)0x00) /*!< endpoint out 0 */ +#define EP0_IN ((uint8_t)0x80) /*!< endpoint in 0 */ +#define EP1_OUT ((uint8_t)0x01) /*!< endpoint out 1 */ +#define EP1_IN ((uint8_t)0x81) /*!< endpoint in 1 */ +#define EP2_OUT ((uint8_t)0x02) /*!< endpoint out 2 */ +#define EP2_IN ((uint8_t)0x82) /*!< endpoint in 2 */ +#define EP3_OUT ((uint8_t)0x03) /*!< endpoint out 3 */ +#define EP3_IN ((uint8_t)0x83) /*!< endpoint in 3 */ + +#endif /* __DRV_USB_REGS_H */ diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usbh_int.h b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usbh_int.h new file mode 100644 index 0000000..5af6e9c --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/drv_usbh_int.h @@ -0,0 +1,49 @@ +/*! + \file drv_usbh_int.h.h + \brief USB host mode interrupt management header file + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#ifndef __DRV_USBH_INT_H +#define __DRV_USBH_INT_H + +#include "drv_usb_host.h" + +typedef struct _usbh_int_cb +{ + uint8_t (*SOF) (usb_core_driver *pudev); +} usbh_int_cb; + +extern usbh_int_cb *usbh_int_fop; + +uint32_t usbh_isr (usb_core_driver *pudev); + +#endif /* __DRV_USBH_INT_H */ diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usb_ch9_std.h b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usb_ch9_std.h new file mode 100644 index 0000000..834e751 --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usb_ch9_std.h @@ -0,0 +1,237 @@ +/*! + \file usb_ch9_std.h + \brief USB 2.0 standard defines + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#ifndef __USB_CH9_STD_H +#define __USB_CH9_STD_H + +#include "usb_conf.h" + +#define USB_DEV_QUALIFIER_DESC_LEN 0x0AU /*!< USB device qualifier descriptor length */ +#define USB_DEV_DESC_LEN 0x12U /*!< USB device descriptor length */ +#define USB_CFG_DESC_LEN 0x09U /*!< USB configuration descriptor length */ +#define USB_ITF_DESC_LEN 0x09U /*!< USB interface descriptor length */ +#define USB_EP_DESC_LEN 0x07U /*!< USB endpoint descriptor length */ +#define USB_OTG_DESC_LEN 0x03U /*!< USB device OTG descriptor length */ + +#define USB_SETUP_PACKET_LEN 0x08U /*!< USB setup packet length */ + +/* bit 7 of bmRequestType: data phase transfer direction */ +#define USB_TRX_MASK 0x80U /*!< USB transfer direction mask */ +#define USB_TRX_OUT 0x00U /*!< USB transfer OUT direction */ +#define USB_TRX_IN 0x80U /*!< USB transfer IN direction */ + +/* bit 6..5 of bmRequestType: request type */ +#define USB_REQTYPE_STRD 0x00U /*!< USB standard request */ +#define USB_REQTYPE_CLASS 0x20U /*!< USB class request */ +#define USB_REQTYPE_VENDOR 0x40U /*!< USB vendor request */ +#define USB_REQTYPE_MASK 0x60U /*!< USB request mask */ + +#define USBD_BUS_POWERED 0x00U /*!< USB bus power supply */ +#define USBD_SELF_POWERED 0x01U /*!< USB self power supply */ + +#define USB_STATUS_REMOTE_WAKEUP 2U /*!< USB is in remote wakeup status */ +#define USB_STATUS_SELF_POWERED 1U /*!< USB is in self powered status */ + +/* bit 4..0 of bmRequestType: recipient type */ +enum _usb_recp_type { + USB_RECPTYPE_DEV = 0x0U, /*!< USB device request type */ + USB_RECPTYPE_ITF = 0x1U, /*!< USB interface request type */ + USB_RECPTYPE_EP = 0x2U, /*!< USB endpoint request type */ + USB_RECPTYPE_MASK = 0x3U /*!< USB request type mask */ +}; + +/* bRequest value */ +enum _usb_request { + USB_GET_STATUS = 0x0U, /*!< USB get status request */ + USB_CLEAR_FEATURE = 0x1U, /*!< USB clear feature request */ + USB_RESERVED2 = 0x2U, + USB_SET_FEATURE = 0x3U, /*!< USB set feature request */ + USB_RESERVED4 = 0x4U, + USB_SET_ADDRESS = 0x5U, /*!< USB set address request */ + USB_GET_DESCRIPTOR = 0x6U, /*!< USB get descriptor request */ + USB_SET_DESCRIPTOR = 0x7U, /*!< USB set descriptor request */ + USB_GET_CONFIGURATION = 0x8U, /*!< USB get configuration request */ + USB_SET_CONFIGURATION = 0x9U, /*!< USB set configuration request */ + USB_GET_INTERFACE = 0xAU, /*!< USB get interface request */ + USB_SET_INTERFACE = 0xBU, /*!< USB set interface request */ + USB_SYNCH_FRAME = 0xCU /*!< USB synchronize frame request */ +}; + +/* descriptor types of USB specifications */ +enum _usb_desctype { + USB_DESCTYPE_DEV = 0x1U, /*!< USB device descriptor type */ + USB_DESCTYPE_CONFIG = 0x2U, /*!< USB configuration descriptor type */ + USB_DESCTYPE_STR = 0x3U, /*!< USB string descriptor type */ + USB_DESCTYPE_ITF = 0x4U, /*!< USB interface descriptor type */ + USB_DESCTYPE_EP = 0x5U, /*!< USB endpoint descriptor type */ + USB_DESCTYPE_DEV_QUALIFIER = 0x6U, /*!< USB device qualtfier descriptor type */ + USB_DESCTYPE_OTHER_SPD_CONFIG = 0x7U, /*!< USB other speed configuration descriptor type */ + USB_DESCTYPE_ITF_POWER = 0x8U, /*!< USB interface power descriptor type */ + USB_DESCTYPE_BOS = 0xFU /*!< USB BOS descriptor type */ +}; + +/* USB Endpoint Descriptor bmAttributes bit definitions */ +/* bits 1..0 : transfer type */ +enum _usbx_type { + USB_EP_ATTR_CTL = 0x0U, /*!< USB control transfer type */ + USB_EP_ATTR_ISO = 0x1U, /*!< USB Isochronous transfer type */ + USB_EP_ATTR_BULK = 0x2U, /*!< USB Bulk transfer type */ + USB_EP_ATTR_INT = 0x3U /*!< USB Interrupt transfer type */ +}; + +/* bits 3..2 : Sync type (only if ISOCHRONOUS) */ +#define USB_EP_ATTR_NOSYNC 0x00 /* No Synchronization */ +#define USB_EP_ATTR_ASYNC 0x04 /* Asynchronous */ +#define USB_EP_ATTR_ADAPTIVE 0x08 /* Adaptive */ +#define USB_EP_ATTR_SYNC 0x0C /* Synchronous */ +#define USB_EP_ATTR_SYNCTYPE 0x0C /* Synchronous type */ + +/* bits 5..4 : usage type (only if ISOCHRONOUS) */ +#define USB_EP_ATTR_DATA 0x00 /* Data endpoint */ +#define USB_EP_ATTR_FEEDBACK 0x10 /* Feedback endpoint */ +#define USB_EP_ATTR_IMPLICIT_FEEDBACK_DATA 0x20 /* Implicit feedback Data endpoint */ +#define USB_EP_ATTR_USAGETYPE 0x30 /* Usage type */ + +#define FEATURE_SELECTOR_EP 0x00 /* USB endpoint feature selector */ +#define FEATURE_SELECTOR_DEV 0x01 /* USB device feature selector */ + +#define BYTE_SWAP(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \ + (uint16_t)(((uint16_t)(*(((uint8_t *)(addr)) + 1U))) << 8U)) + +#define BYTE_LOW(x) ((uint8_t)((x) & 0x00FFU)) +#define BYTE_HIGH(x) ((uint8_t)(((x) & 0xFF00U) >> 8U)) + +#define USB_MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#define USB_DEFAULT_CONFIG 0U + +/* USB classes */ +#define USB_CLASS_HID 0x03U /*!< USB HID class */ +#define USB_CLASS_MSC 0x08U /*!< USB MSC class */ + +/* use the following values when USB host need to get descriptor */ +#define USBH_DESC(x) (((x)<< 8U) & 0xFF00U) + +/* as per usb specs 9.2.6.4 :standard request with data request timeout: 5sec + standard request with no data stage timeout : 50ms */ +#define DATA_STAGE_TIMEOUT 5000U /*!< USB data stage timeout*/ +#define NODATA_STAGE_TIMEOUT 50U /*!< USB no data stage timeout*/ + +#pragma pack(1) + +/* USB standard device request structure */ +typedef struct _usb_req { + uint8_t bmRequestType; /*!< type of request */ + uint8_t bRequest; /*!< request of setup packet */ + uint16_t wValue; /*!< value of setup packet */ + uint16_t wIndex; /*!< index of setup packet */ + uint16_t wLength; /*!< length of setup packet */ +} usb_req; + +/* USB setup packet define */ +typedef union _usb_setup { + uint8_t data[8]; + + usb_req req; +} usb_setup; + +/* USB descriptor defines */ + +typedef struct _usb_desc_header { + uint8_t bLength; /*!< size of the descriptor */ + uint8_t bDescriptorType; /*!< type of the descriptor */ +} usb_desc_header; + +typedef struct _usb_desc_dev { + usb_desc_header header; /*!< descriptor header, including type and size */ + + uint16_t bcdUSB; /*!< BCD of the supported USB specification */ + uint8_t bDeviceClass; /*!< USB device class */ + uint8_t bDeviceSubClass; /*!< USB device subclass */ + uint8_t bDeviceProtocol; /*!< USB device protocol */ + uint8_t bMaxPacketSize0; /*!< size of the control (address 0) endpoint's bank in bytes */ + uint16_t idVendor; /*!< vendor ID for the USB product */ + uint16_t idProduct; /*!< unique product ID for the USB product */ + uint16_t bcdDevice; /*!< product release (version) number */ + uint8_t iManufacturer; /*!< string index for the manufacturer's name */ + uint8_t iProduct; /*!< string index for the product name/details */ + uint8_t iSerialNumber; /*!< string index for the product's globally unique hexadecimal serial number */ + uint8_t bNumberConfigurations; /*!< total number of configurations supported by the device */ +} usb_desc_dev; + +typedef struct _usb_desc_config { + usb_desc_header header; /*!< descriptor header, including type and size */ + + uint16_t wTotalLength; /*!< size of the configuration descriptor header,and all sub descriptors inside the configuration */ + uint8_t bNumInterfaces; /*!< total number of interfaces in the configuration */ + uint8_t bConfigurationValue; /*!< configuration index of the current configuration */ + uint8_t iConfiguration; /*!< index of a string descriptor describing the configuration */ + uint8_t bmAttributes; /*!< configuration attributes */ + uint8_t bMaxPower; /*!< maximum power consumption of the device while in the current configuration */ +} usb_desc_config; + +typedef struct _usb_desc_itf { + usb_desc_header header; /*!< descriptor header, including type and size */ + + uint8_t bInterfaceNumber; /*!< index of the interface in the current configuration */ + uint8_t bAlternateSetting; /*!< alternate setting for the interface number */ + uint8_t bNumEndpoints; /*!< total number of endpoints in the interface */ + uint8_t bInterfaceClass; /*!< interface class ID */ + uint8_t bInterfaceSubClass; /*!< interface subclass ID */ + uint8_t bInterfaceProtocol; /*!< interface protocol ID */ + uint8_t iInterface; /*!< index of the string descriptor describing the interface */ +} usb_desc_itf; + +typedef struct _usb_desc_ep { + usb_desc_header header; /*!< descriptor header, including type and size. */ + + uint8_t bEndpointAddress; /*!< logical address of the endpoint */ + uint8_t bmAttributes; /*!< endpoint attributes */ + uint16_t wMaxPacketSize; /*!< size of the endpoint bank, in bytes */ + + uint8_t bInterval; /*!< polling interval in milliseconds for the endpoint if it is an INTERRUPT or ISOCHRONOUS type */ +#ifdef AUDIO_ENDPOINT + uint8_t bRefresh; /*!< reset to 0 */ + uint8_t bSynchAddress; /*!< reset to 0 */ +#endif +} usb_desc_ep; + +typedef struct _usb_desc_LANGID { + usb_desc_header header; /*!< descriptor header, including type and size. */ + uint16_t wLANGID; /*!< LANGID code */ +} usb_desc_LANGID; + +#pragma pack() + +#endif /* __USB_CH9_STD_H */ diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usbh_core.h b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usbh_core.h new file mode 100644 index 0000000..18db18c --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usbh_core.h @@ -0,0 +1,229 @@ +/*! + \file usbh_core.h + \brief USB host core state machine header file + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#ifndef __USBH_CORE_H +#define __USBH_CORE_H + +#include "usbh_conf.h" +#include "drv_usb_host.h" + +#define MSC_CLASS 0x08U +#define HID_CLASS 0x03U +#define MSC_PROTOCOL 0x50U +#define CBI_PROTOCOL 0x01U + +#define USBH_MAX_ERROR_COUNT 8U + +#define USBH_DEV_ADDR_DEFAULT 0U +#define USBH_DEV_ADDR 1U + +#define HOST_USER_SELECT_CONFIGURATION 1 +#define HOST_USER_CLASS_ACTIVE 2 +#define HOST_USER_CLASS_SELECTED 3 +#define HOST_USER_CONNECTION 4 +#define HOST_USER_DISCONNECTION 5 +#define HOST_USER_UNRECOVERED_ERROR 6 +#define HOST_USER_CLASS_FAILED 7 + +typedef enum +{ + USBH_OK = 0U, + USBH_BUSY, + USBH_FAIL, + USBH_NOT_SUPPORTED, + USBH_UNRECOVERED_ERROR, + USBH_SPEED_UNKNOWN_ERROR, + USBH_APPLY_DEINIT +} usbh_status; + +/* USB host global operation state */ +typedef enum +{ + HOST_DEFAULT = 0U, + HOST_DETECT_DEV_SPEED, + HOST_DEV_ATTACHED, + HOST_DEV_DETACHED, + HOST_ENUM, + HOST_CLASS_ENUM, + HOST_CLASS_HANDLER, + HOST_USER_INPUT, + HOST_SUSPENDED, + HOST_CHECK_CLASS, + HOST_ERROR +} usb_host_state; + +/* USB host enumeration state */ +typedef enum +{ + ENUM_DEFAULT = 0U, + ENUM_GET_DEV_DESC, + ENUM_SET_ADDR, + ENUM_GET_CFG_DESC, + ENUM_GET_CFG_DESC_SET, + ENUM_GET_STR_DESC, + ENUM_SET_CONFIGURATION, + ENUM_DEV_CONFIGURED +} usbh_enum_state; + +/* USB host control transfer state */ +typedef enum +{ + CTL_IDLE = 0U, + CTL_SETUP, + CTL_DATA_IN, + CTL_DATA_OUT, + CTL_STATUS_IN, + CTL_STATUS_OUT, + CTL_ERROR, + CTL_FINISH +} usbh_ctl_state; + +/* user action state */ +typedef enum +{ + USBH_USER_NO_RESP = 0U, + USBH_USER_RESP_OK = 1U, +} usbh_user_status; + +/* control transfer information */ +typedef struct _usbh_control +{ + uint8_t pipe_in_num; + uint8_t pipe_out_num; + uint8_t max_len; + uint8_t error_count; + + uint8_t *buf; + uint16_t ctl_len; + uint16_t timer; + + usb_setup setup; + usbh_ctl_state ctl_state; +} usbh_control; + +/* USB device property */ +typedef struct +{ + uint8_t addr; + uint32_t speed; + + usb_desc_dev dev_desc; + usb_desc_config cfg_desc; + usb_desc_itf itf_desc[USBH_MAX_INTERFACES_NUM]; + usb_desc_ep ep_desc[USBH_MAX_INTERFACES_NUM][USBH_MAX_EP_NUM]; +} usb_dev_prop; + +/** + * @brief Device class callbacks + */ +typedef struct +{ + usbh_status (*class_init) (usb_core_driver *pudev, void *phost); + void (*class_deinit) (usb_core_driver *pudev, void *phost); + usbh_status (*class_requests) (usb_core_driver *pudev, void *phost); + usbh_status (*class_machine) (usb_core_driver *pudev, void *phost); +} usbh_class_cb; + +/** + * @brief User callbacks + */ +typedef struct +{ + void (*dev_init) (void); + void (*dev_deinit) (void); + void (*dev_attach) (void); + void (*dev_reset) (void); + void (*dev_detach) (void); + void (*dev_over_currented) (void); + void (*dev_speed_detected) (uint32_t dev_speed); + void (*dev_devdesc_assigned) (void *dev_desc); + void (*dev_address_set) (void); + + void (*dev_cfgdesc_assigned) (usb_desc_config *cfg_desc, + usb_desc_itf *itf_desc, + usb_desc_ep *ep_desc); + + void (*dev_mfc_str) (void *mfc_str); + void (*dev_prod_str) (void *prod_str); + void (*dev_seral_str) (void *serial_str); + void (*dev_enumerated) (void); + usbh_user_status (*dev_user_input) (void); + int (*dev_user_app) (void); + void (*dev_not_supported) (void); + void (*dev_error) (void); +} usbh_user_cb; + +/** + * @brief Host information + */ +typedef struct _usbh_host +{ + usb_host_state cur_state; /*!< host state machine value */ + usb_host_state backup_state; /*!< backup of previous state machine value */ + usbh_enum_state enum_state; /*!< enumeration state machine */ + usbh_control control; /*!< USB host control state machine */ + usb_dev_prop dev_prop; /*!< USB device properity */ + + usbh_class_cb *class_cb; /*!< USB class callback */ + usbh_user_cb *usr_cb; /*!< USB user callback */ + void (* pUser )(struct _usbh_host *pHandle, uint8_t id); +} usbh_host; + + +/* USB host stack initializations */ +void usbh_init (usb_core_driver *pudev, usb_core_enum core, usbh_host *puhost,void (*pUsrFunc)(usbh_host *phost, uint8_t )); + +/* de-initialize USB host */ +usbh_status usbh_deinit (usb_core_driver *pudev, usbh_host *puhost); + +/* USB host core main state machine process */ +void usbh_core_task (usb_core_driver *pudev, usbh_host *puhost); + +/* handle the error on USB host side */ +void usbh_error_handler (usbh_host *puhost, usbh_status ErrType); + +/* get USB URB state */ +static inline usb_urb_state usbh_urbstate_get (usb_core_driver *pudev, uint8_t pp_num) +{ + return pudev->host.pipe[pp_num].urb_state; +} + +/* get USB transfer data count */ +static inline uint32_t usbh_xfercount_get (usb_core_driver *pudev, uint8_t pp_num) +{ + return pudev->host.backup_xfercount[pp_num]; +} + +#endif /* __USBH_CORE_H */ + diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usbh_enum.h b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usbh_enum.h new file mode 100644 index 0000000..b82eae2 --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usbh_enum.h @@ -0,0 +1,78 @@ +/*! + \file usbh_enum.h + \brief USB host mode USB enumeration header file + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#ifndef __USBH_ENUM_H +#define __USBH_ENUM_H + +#include "usb_conf.h" +#include "usbh_core.h" + +/* get the next descriptor header */ +usb_desc_header *usbh_nextdesc_get (uint8_t *pbuf, uint16_t *ptr); + +/* configure USB control status parameters */ +void usbh_ctlstate_config (usbh_host *puhost, uint8_t *buf, uint16_t len); + +/* get device descriptor from the USB device */ +usbh_status usbh_devdesc_get (usb_core_driver *pudev, usbh_host *puhost, uint8_t len); + +/* get configuration descriptor from the USB device */ +usbh_status usbh_cfgdesc_get (usb_core_driver *pudev, usbh_host *puhost, uint16_t len); + +/* get string descriptor from the USB device */ +usbh_status usbh_strdesc_get (usb_core_driver *pudev, + usbh_host *puhost, + uint8_t str_index, + uint8_t *buf, + uint16_t len); + +/* set the configuration value to the connected device */ +usbh_status usbh_setcfg (usb_core_driver *pudev, usbh_host *puhost, uint16_t config); + +/* set the address to the connected device */ +usbh_status usbh_setaddress (usb_core_driver *pudev, usbh_host *puhost, uint8_t dev_addr); + +/* clear or disable a specific feature */ +usbh_status usbh_clrfeature (usb_core_driver *pudev, + usbh_host *puhost, + uint8_t ep_num, + uint8_t pp_num); + +/* set the interface value to the connected device */ +usbh_status usbh_setinterface (usb_core_driver *pudev, + usbh_host *puhost, + uint8_t ep_num, + uint8_t alter_setting); + +#endif /* __USBH_ENUM_H */ diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usbh_pipe.h b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usbh_pipe.h new file mode 100644 index 0000000..a0d12e7 --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usbh_pipe.h @@ -0,0 +1,70 @@ +/*! + \file usbh_pipe.h + \brief USB host mode pipe header file + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#ifndef __USBH_PIPE_H +#define __USBH_PIPE_H + +#include "usbh_core.h" + +#define HC_MAX 8U + +#define HC_OK 0x0000U +#define HC_USED 0x8000U +#define HC_ERROR 0xFFFFU +#define HC_USED_MASK 0x7FFFU + +/* allocate a new pipe */ +uint8_t usbh_pipe_allocate (usb_core_driver *pudev, uint8_t ep_addr); + +/* delete all USB host pipe */ +uint8_t usbh_pipe_delete (usb_core_driver *pudev); + +/* free a pipe */ +uint8_t usbh_pipe_free (usb_core_driver *pudev, uint8_t pp_num); + +/* create a pipe */ +uint8_t usbh_pipe_create (usb_core_driver *pudev, + usb_dev_prop *udev, + uint8_t pp_num, + uint8_t ep_type, + uint16_t ep_mpl); + +/* modify a pipe */ +uint8_t usbh_pipe_update (usb_core_driver *pudev, + uint8_t pp_num, + uint8_t dev_addr, + uint32_t dev_speed, + uint16_t ep_mpl); + +#endif /* __USBH_PIPE_H */ diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usbh_transc.h b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usbh_transc.h new file mode 100644 index 0000000..f76d132 --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Include/usbh_transc.h @@ -0,0 +1,54 @@ +/*! + \file usbh_transc.h + \brief USB host mode transactions header file + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#ifndef __USBH_TRANSC_H +#define __USBH_TRANSC_H + +#include "usb_conf.h" +#include "usbh_core.h" + +/* send the setup packet to the USB device */ +usbh_status usbh_ctlsetup_send (usb_core_driver *pudev, uint8_t *buf, uint8_t pp_num); + +/* send a data packet to the USB device */ +usbh_status usbh_data_send (usb_core_driver *pudev, uint8_t *buf, uint8_t pp_num, uint16_t len); + +/* receive a data packet from the USB device */ +usbh_status usbh_data_recev (usb_core_driver *pudev, uint8_t *buf, uint8_t pp_num, uint16_t len); + +/* USB control transfer handler */ +usbh_status usbh_ctl_handler (usb_core_driver *pudev, usbh_host *puhost); + +#endif /* __USBH_TRANSC_H */ + diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/drv_usb_core.c b/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/drv_usb_core.c new file mode 100644 index 0000000..b4cff05 --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/drv_usb_core.c @@ -0,0 +1,319 @@ +/*! + \file drv_usb_core.c + \brief USB core driver which can operate in host and device mode + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#include "drv_usb_core.h" +#include "drv_usb_hw.h" + +/*! + \brief config USB core to soft reset + \param[in] usb_regs: USB core registers + \param[out] none + \retval none +*/ +static void usb_core_reset (usb_core_regs *usb_regs) +{ + /* enable core soft reset */ + usb_regs->gr->GRSTCTL |= GRSTCTL_CSRST; + + /* wait for the core to be soft reset */ + while (usb_regs->gr->GRSTCTL & GRSTCTL_CSRST); + + /* wait for addtional 3 PHY clocks */ + usb_udelay(3); +} + +/*! + \brief config USB core basic + \param[in] usb_basic: pointer to usb capabilities + \param[in] usb_regs: USB core registers + \param[in] usb_core: USB core + \param[out] none + \retval operation status +*/ +usb_status usb_basic_init (usb_core_basic *usb_basic, + usb_core_regs *usb_regs, + usb_core_enum usb_core) +{ + uint32_t i = 0, reg_base = 0; + + /* config USB default transfer mode as FIFO mode */ + usb_basic->transfer_mode = USB_USE_FIFO; + + /* USB default speed is full-speed */ + usb_basic->core_speed = USB_SPEED_FULL; + + usb_basic->core_enum = usb_core; + + switch (usb_core) { + case USB_CORE_ENUM_HS: + reg_base = USBHS_REG_BASE; + + /* set the host channel numbers */ + usb_basic->num_pipe = USBHS_MAX_CHANNEL_COUNT; + + /* set the device endpoint numbers */ + usb_basic->num_ep = USBHS_MAX_EP_COUNT; + +#ifdef USB_ULPI_PHY_ENABLED + usb_basic->phy_itf = USB_ULPI_PHY; +#else + usb_basic->phy_itf = USB_EMBEDDED_PHY; +#endif /* USB_ULPI_PHY_ENABLED */ + +#ifdef USB_HS_INTERNAL_DMA_ENABLED + bp->transfer_mode = USB_USE_DMA; +#endif /* USB_HS_INTERNAL_DMA_ENABLED */ + break; + + case USB_CORE_ENUM_FS: + reg_base = USBFS_REG_BASE; + + /* set the host channel numbers */ + usb_basic->num_pipe = USBFS_MAX_CHANNEL_COUNT; + + /* set the device endpoint numbers */ + usb_basic->num_ep = USBFS_MAX_EP_COUNT; + + /* USBFS core use embedded physical layer */ + usb_basic->phy_itf = USB_EMBEDDED_PHY; + break; + + default: + return USB_FAIL; + } + + usb_basic->sof_enable = USB_SOF_OUTPUT; + usb_basic->low_power = USB_LOW_POWER; + + /* assign main registers address */ + *usb_regs = (usb_core_regs) { + .gr = (usb_gr*) (reg_base + USB_REG_OFFSET_CORE), + .hr = (usb_hr*) (reg_base + USB_REG_OFFSET_HOST), + .dr = (usb_dr*) (reg_base + USB_REG_OFFSET_DEV), + + .HPCS = (uint32_t*) (reg_base + USB_REG_OFFSET_PORT), + .PWRCLKCTL = (uint32_t*) (reg_base + USB_REG_OFFSET_PWRCLKCTL) + }; + + /* assign device endpoint registers address */ + for (i = 0; i < usb_basic->num_ep; i++) { + usb_regs->er_in[i] = (usb_erin *) \ + (reg_base + USB_REG_OFFSET_EP_IN + (i * USB_REG_OFFSET_EP)); + + usb_regs->er_out[i] = (usb_erout *)\ + (reg_base + USB_REG_OFFSET_EP_OUT + (i * USB_REG_OFFSET_EP)); + } + + /* assign host pipe registers address */ + for (i = 0; i < usb_basic->num_pipe; i++) { + usb_regs->pr[i] = (usb_pr *) \ + (reg_base + USB_REG_OFFSET_CH_INOUT + (i * USB_REG_OFFSET_CH)); + + usb_regs->DFIFO[i] = (uint32_t *) \ + (reg_base + USB_DATA_FIFO_OFFSET + (i * USB_DATA_FIFO_SIZE)); + } + + return USB_OK; +} + +/*! + \brief initializes the USB controller registers and + prepares the core device mode or host mode operation + \param[in] bp: usb capabilities + \param[in] core_regs: usb core registers + \param[out] none + \retval operation status +*/ +usb_status usb_core_init (usb_core_basic usb_basic, usb_core_regs *usb_regs) +{ + uint32_t reg_value = usb_regs->gr->GCCFG; + + /* disable USB global interrupt */ + usb_regs->gr->GAHBCS &= ~GAHBCS_GINTEN; + + if (USB_ULPI_PHY == usb_basic.phy_itf) { + reg_value &= ~GCCFG_PWRON; + + if (usb_basic.sof_enable) { + reg_value |= GCCFG_SOFOEN; + } + + usb_regs->gr->GCCFG = GCCFG_SOFOEN; + + /* init the ULPI interface */ + usb_regs->gr->GUSBCS &= ~(GUSBCS_EMBPHY | GUSBCS_ULPIEOI); + +#ifdef USBHS_EXTERNAL_VBUS_ENABLED + /* use external VBUS driver */ + usb_regs->gr->GUSBCS |= GUSBCS_ULPIEVD; +#else + /* use internal VBUS driver */ + usb_regs->gr->GUSBCS &= ~GUSBCS_ULPIEVD; +#endif + + /* soft reset the core */ + usb_core_reset (usb_regs); + } else { + usb_regs->gr->GUSBCS |= GUSBCS_EMBPHY; + + /* soft reset the core */ + usb_core_reset (usb_regs); + + /* active the transceiver and enable vbus sensing */ + reg_value = GCCFG_PWRON | GCCFG_VBUSACEN | GCCFG_VBUSBCEN; + +#ifndef VBUS_SENSING_ENABLED + reg_value |= GCCFG_VBUSIG; +#endif /* VBUS_SENSING_ENABLED */ + + /* enable SOF output */ + if (usb_basic.sof_enable) { + reg_value |= GCCFG_SOFOEN; + } + + usb_regs->gr->GCCFG = reg_value; + + usb_mdelay(20); + } + + if (USB_USE_DMA == usb_basic.transfer_mode) { + usb_regs->gr->GAHBCS |= GAHBCS_DMAEN; + usb_regs->gr->GAHBCS &= ~GAHBCS_BURST; + usb_regs->gr->GAHBCS |= DMA_INCR8; + } + +#ifdef USE_OTG_MODE + + /* enable USB OTG features */ + usb_regs->gr->GUSBCS |= GUSBCS_HNPCAP | GUSBCS_SRPCAP; + + /* enable the USB wakeup and suspend interrupts */ + usb_regs->gr->GINTF = 0xBFFFFFFFU; + + usb_regs->gr->GINTEN = GINTEN_WKUPIE | GINTEN_SPIE | \ + GINTEN_OTGIE | GINTEN_SESIE | GINTEN_CIDPSCIE; + +#endif /* USE_OTG_MODE */ + + return USB_OK; +} + +/*! + \brief write a packet into the Tx FIFO associated with the endpoint + \param[in] core_regs: usb core registers + \param[in] src_buf: pointer to source buffer + \param[in] fifo_num: FIFO number which is in (0..3) + \param[in] byte_count: packet byte count + \param[out] none + \retval operation status +*/ +usb_status usb_txfifo_write (usb_core_regs *usb_regs, + uint8_t *src_buf, + uint8_t fifo_num, + uint16_t byte_count) +{ + uint32_t word_count = (byte_count + 3U) / 4U; + + __IO uint32_t *fifo = usb_regs->DFIFO[fifo_num]; + + while (word_count-- > 0) { + *fifo = *((__packed uint32_t *)src_buf); + + src_buf += 4U; + } + + return USB_OK; +} + +/*! + \brief read a packet from the Rx FIFO associated with the endpoint + \param[in] core_regs: usb core registers + \param[in] dest_buf: pointer to destination buffer + \param[in] byte_count: packet byte count + \param[out] none + \retval void type pointer +*/ +void *usb_rxfifo_read (usb_core_regs *usb_regs, uint8_t *dest_buf, uint16_t byte_count) +{ + uint32_t word_count = (byte_count + 3U) / 4U; + + __IO uint32_t *fifo = usb_regs->DFIFO[0]; + + while (word_count-- > 0) { + *(__packed uint32_t *)dest_buf = *fifo; + + dest_buf += 4U; + } + + return ((void *)dest_buf); +} + +/*! + \brief flush a Tx FIFO or all Tx FIFOs + \param[in] core_regs: pointer to usb core registers + \param[in] fifo_num: FIFO number which is in (0..3) + \param[out] none + \retval operation status +*/ +usb_status usb_txfifo_flush (usb_core_regs *usb_regs, uint8_t fifo_num) +{ + usb_regs->gr->GRSTCTL = ((uint32_t)fifo_num << 6U) | GRSTCTL_TXFF; + + /* wait for Tx FIFO flush bit is set */ + while (usb_regs->gr->GRSTCTL & GRSTCTL_TXFF); + + /* wait for 3 PHY clocks*/ + usb_udelay(3); + + return USB_OK; +} + +/*! + \brief flush the entire Rx FIFO + \param[in] core_regs: pointer to usb core registers + \param[out] none + \retval operation status +*/ +usb_status usb_rxfifo_flush (usb_core_regs *usb_regs) +{ + usb_regs->gr->GRSTCTL = GRSTCTL_RXFF; + + /* wait for Rx FIFO flush bit is set */ + while (usb_regs->gr->GRSTCTL & GRSTCTL_RXFF); + + /* wait for 3 PHY clocks */ + usb_udelay(3); + + return USB_OK; +} diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/drv_usb_host.c b/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/drv_usb_host.c new file mode 100644 index 0000000..747d40c --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/drv_usb_host.c @@ -0,0 +1,514 @@ +/*! + \file drv_usb_host.c + \brief USB host mode low level driver + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#include "../Include/drv_usb_hw.h" +#include "../Include/drv_usb_core.h" +#include "../Include/drv_usb_host.h" + +const uint32_t PIPE_DPID[] = { + PIPE_DPID_DATA0, + PIPE_DPID_DATA1 +}; + +//__STATIC_INLINE uint8_t usb_frame_even (usb_core_driver *pudev) +uint32_t usb_frame_even (usb_core_driver *pudev) +{ + return !(pudev->regs.hr->HFINFR & 0x01U); +} + +//__STATIC_INLINE void usb_phyclock_config (usb_core_driver *pudev, uint8_t clock) +void usb_phyclock_config (usb_core_driver *pudev, uint8_t clock) +{ + pudev->regs.hr->HCTL &= ~HCTL_CLKSEL; + pudev->regs.hr->HCTL |= clock; +} + +//__STATIC_INLINE uint32_t usb_port_read (usb_core_driver *pudev) +uint32_t usb_port_read (usb_core_driver *pudev) +{ + return *pudev->regs.HPCS & ~(HPCS_PE | HPCS_PCD | HPCS_PEDC); +} + +//__STATIC_INLINE uint32_t usb_curspeed_get (usb_core_driver *pudev) + +uint32_t usb_curspeed_get (usb_core_driver *pudev) +{ + return *pudev->regs.HPCS & HPCS_PS; +} + +uint32_t usb_curframe_get (usb_core_driver *pudev) +{ + return (pudev->regs.hr->HFINFR & 0xFFFFU); +} + +/*! + \brief initializes USB core for host mode + \param[in] pudev: pointer to selected usb host + \param[out] none + \retval operation status +*/ +usb_status usb_host_init (usb_core_driver *pudev) +{ + uint32_t i = 0, inten = 0U; + + uint32_t nptxfifolen = 0U; + uint32_t ptxfifolen = 0U; + + pudev->regs.gr->GUSBCS &= ~GUSBCS_FDM; + pudev->regs.gr->GUSBCS |= GUSBCS_FHM; + + /* restart the PHY Clock */ + *pudev->regs.PWRCLKCTL = 0U; + + /* initialize host configuration register */ + if (USB_ULPI_PHY == pudev->bp.phy_itf) { + usb_phyclock_config (pudev, HCTL_30_60MHZ); + } else { + usb_phyclock_config (pudev, HCTL_48MHZ); + } + + usb_port_reset (pudev); + + /* support FS/LS only */ + pudev->regs.hr->HCTL &= ~HCTL_SPDFSLS; + + /* configure data FIFOs size */ +#ifdef USB_FS_CORE + if (USB_CORE_ENUM_FS == pudev->bp.core_enum) { + /* set Rx FIFO size */ + pudev->regs.gr->GRFLEN = USB_RX_FIFO_FS_SIZE; + + /* set non-periodic Tx FIFO size and address */ + nptxfifolen |= USB_RX_FIFO_FS_SIZE; + nptxfifolen |= USB_HTX_NPFIFO_FS_SIZE << 16U; + pudev->regs.gr->DIEP0TFLEN_HNPTFLEN = nptxfifolen; + + /* set periodic Tx FIFO size and address */ + ptxfifolen |= USB_RX_FIFO_FS_SIZE + USB_HTX_PFIFO_FS_SIZE; + ptxfifolen |= USB_HTX_PFIFO_FS_SIZE << 16U; + pudev->regs.gr->HPTFLEN = ptxfifolen; + } +#endif /* USB_FS_CORE */ + +#ifdef USB_HS_CORE + if (USB_CORE_HS == pudev->cfg.core) { + /* set Rx FIFO size */ + pudev->regs.gr->GRFLEN = USBHS_RX_FIFO_SIZE; + + /* set non-periodic Tx FIFO size and address */ + nptxfifolen |= USBHS_RX_FIFO_SIZE; + nptxfifolen |= USBHS_HTX_NPFIFO_SIZE; + pudev->regs.gr->DIEP0TFLEN_HNPTFLEN = nptxfifolen; + + /* set periodic Tx FIFO size and address */ + ptxfifolen |= USBHS_RX_FIFO_SIZE + USBHS_HTX_PFIFO_SIZE; + ptxfifolen |= USBHS_HTX_PFIFO_SIZE; + pudev->regs.gr->HPTFLEN = ptxfifolen; + } +#endif + +#ifdef USE_OTG_MODE + + /* clear host set hnp enable in the usb_otg control register */ + pudev->regs.gr->GOTGCS &= ~GOTGCS_HHNPEN; + +#endif + + /* disable all interrupts */ + pudev->regs.gr->GINTEN = 0U; + + /* clear any pending USB OTG interrupts */ + pudev->regs.gr->GOTGINTF = 0xFFFFFFFFU; + + /* enable the USB wakeup and suspend interrupts */ + pudev->regs.gr->GINTF = 0xBFFFFFFFU; + + /* make sure the FIFOs are flushed */ + + /* flush all Tx FIFOs in device or host mode */ + usb_txfifo_flush (&pudev->regs, 0x10U); + + /* flush the entire Rx FIFO */ + usb_rxfifo_flush (&pudev->regs); + + /* clear all pending host channel interrupts */ + for (i = 0U; i < pudev->bp.num_pipe; i++) { + pudev->regs.pr[i]->HCHINTF = 0xFFFFFFFFU; + pudev->regs.pr[i]->HCHINTEN = 0U; + } + +#ifndef USE_OTG_MODE + usb_portvbus_switch (pudev, 1U); +#endif /* USE_OTG_MODE */ + + pudev->regs.gr->GINTEN = GINTEN_WKUPIE | GINTEN_SPIE; + + /* enable host_mode-related interrupts */ + if (USB_USE_FIFO == pudev->bp.transfer_mode) { + inten = GINTEN_RXFNEIE; + } + + inten |= GINTEN_HPIE | GINTEN_HCIE | GINTEN_ISOINCIE; + + pudev->regs.gr->GINTEN |= inten; + + inten = GINTEN_DISCIE | GINTEN_SOFIE; + + pudev->regs.gr->GINTEN &= ~inten; + + pudev->regs.gr->GAHBCS |= GAHBCS_GINTEN; + + return USB_OK; +} + +/*! + \brief control the VBUS to power + \param[in] pudev: pointer to selected usb host + \param[in] state: VBUS state + \param[out] none + \retval none +*/ +void usb_portvbus_switch (usb_core_driver *pudev, uint8_t state) +{ + uint32_t port = 0U; + + /* enable or disable the external charge pump */ + usb_vbus_drive (state); + + /* turn on the host port power. */ + port = usb_port_read (pudev); + + if (!(port & HPCS_PP) && (1U == state)) { + port |= HPCS_PP; + } + + if ((port & HPCS_PP) && (0U == state)) { + port &= ~HPCS_PP; + } + + *pudev->regs.HPCS = port; + + usb_mdelay (200U); +} + +/*! + \brief reset host port + \param[in] pudev: pointer to usb device + \param[out] none + \retval operation status +*/ +uint32_t usb_port_reset (usb_core_driver *pudev) +{ + __IO uint32_t port = usb_port_read (pudev); + + *pudev->regs.HPCS = port | HPCS_PRST; + + usb_mdelay (100U); /* see note */ + + *pudev->regs.HPCS = port & ~HPCS_PRST; + + usb_mdelay (20U); + + return 1; +} + +/*! + \brief initialize host pipe + \param[in] pudev: pointer to usb device + \param[in] pipe_num: host pipe number which is in (0..7) + \param[out] none + \retval operation status +*/ +usb_status usb_pipe_init (usb_core_driver *pudev, uint8_t pipe_num) +{ + usb_status status = USB_OK; + + __IO uint32_t pp_ctl = 0U; + __IO uint32_t pp_inten = HCHINTEN_TFIE; + + usb_pipe *pp = &pudev->host.pipe[pipe_num]; + + /* clear old interrupt conditions for this host channel */ + pudev->regs.pr[pipe_num]->HCHINTF = 0xFFFFFFFFU; + + if (USB_USE_DMA == pudev->bp.transfer_mode) { + pp_inten |= HCHINTEN_DMAERIE; + } + + if (pp->ep.dir) { + pp_inten |= HCHINTEN_BBERIE; + } + + /* enable channel interrupts required for this transfer */ + switch (pp->ep.type) { + case USB_EPTYPE_CTRL: + case USB_EPTYPE_BULK: + pp_inten |= HCHINTEN_STALLIE | HCHINTEN_USBERIE \ + | HCHINTEN_DTERIE | HCHINTEN_NAKIE; + + if (!pp->ep.dir) { + pp_inten |= HCHINTEN_NYETIE; + + if (pp->ping) { + pp_inten |= HCHINTEN_ACKIE; + } + } + break; + + case USB_EPTYPE_INTR: + pp_inten |= HCHINTEN_STALLIE | HCHINTEN_USBERIE | HCHINTEN_DTERIE \ + | HCHINTEN_NAKIE | HCHINTEN_REQOVRIE; + break; + + case USB_EPTYPE_ISOC: + pp_inten |= HCHINTEN_REQOVRIE | HCHINTEN_ACKIE; + + if (pp->ep.dir) { + pp_inten |= HCHINTEN_USBERIE; + } + break; + + default: + break; + } + + pudev->regs.pr[pipe_num]->HCHINTEN = pp_inten; + + /* enable the top level host channel interrupt */ + pudev->regs.hr->HACHINTEN |= 1U << pipe_num; + + /* make sure host channel interrupts are enabled */ + pudev->regs.gr->GINTEN |= GINTEN_HCIE; + + /* program the host channel control register */ + pp_ctl |= PIPE_CTL_DAR(pp->dev_addr); + pp_ctl |= PIPE_CTL_EPNUM(pp->ep.num); + pp_ctl |= PIPE_CTL_EPDIR(pp->ep.dir); + pp_ctl |= PIPE_CTL_EPTYPE(pp->ep.type); + pp_ctl |= PIPE_CTL_LSD(pp->dev_speed == PORT_SPEED_LOW); + + pp_ctl |= pp->ep.mps; + pp_ctl |= ((uint32_t)(pp->ep.type == USB_EPTYPE_INTR) << 29U) & HCHCTL_ODDFRM; + + pudev->regs.pr[pipe_num]->HCHCTL = pp_ctl; + + return status; +} + +/*! + \brief prepare host channel for transferring packets + \param[in] pudev: pointer to usb device + \param[in] pipe_num: host pipe number which is in (0..7) + \param[out] none + \retval operation status +*/ +usb_status usb_pipe_xfer (usb_core_driver *pudev, uint8_t pipe_num) +{ + usb_status status = USB_OK; + + uint16_t dword_len = 0U; + uint16_t packet_count = 0U; + + __IO uint32_t pp_ctl = 0U; + + usb_pipe *pp = &pudev->host.pipe[pipe_num]; + + uint16_t max_packet_len = pp->ep.mps; + + /* compute the expected number of packets associated to the transfer */ + if (pp->xfer_len > 0U) { + packet_count = (pp->xfer_len + max_packet_len - 1U) / max_packet_len; + + if (packet_count > HC_MAX_PACKET_COUNT) { + packet_count = HC_MAX_PACKET_COUNT; + pp->xfer_len = packet_count * max_packet_len; + } + } else { + packet_count = 1U; + } + + if (pp->ep.dir) { + pp->xfer_len = packet_count * max_packet_len; + } + + /* initialize the host channel transfer information */ + pudev->regs.pr[pipe_num]->HCHLEN = pp->xfer_len | pp->DPID | PIPE_XFER_PCNT(packet_count); + + if (USB_USE_DMA == pudev->bp.transfer_mode) { + pudev->regs.pr[pipe_num]->HCHDMAADDR = (unsigned int)pp->xfer_buf; + } + + pp_ctl = pudev->regs.pr[pipe_num]->HCHCTL; + + if (usb_frame_even(pudev)) { + pp_ctl |= HCHCTL_ODDFRM; + } else { + pp_ctl &= ~HCHCTL_ODDFRM; + } + + /* set host channel enabled */ + pp_ctl |= HCHCTL_CEN; + pp_ctl &= ~HCHCTL_CDIS; + + pudev->regs.pr[pipe_num]->HCHCTL = pp_ctl; + + if (USB_USE_FIFO == pudev->bp.transfer_mode) { + if ((0U == pp->ep.dir) && (pp->xfer_len > 0U)) { + switch (pp->ep.type) { + /* non-periodic transfer */ + case USB_EPTYPE_CTRL: + case USB_EPTYPE_BULK: + dword_len = (pp->xfer_len + 3U) / 4U; + + /* check if there is enough space in fifo space */ + if (dword_len > (pudev->regs.gr->HNPTFQSTAT & HNPTFQSTAT_NPTXFS)) { + /* need to process data in nptxfempty interrupt */ + pudev->regs.gr->GINTEN |= GINTEN_NPTXFEIE; + } + break; + + /* periodic transfer */ + case USB_EPTYPE_INTR: + case USB_EPTYPE_ISOC: + dword_len = (pp->xfer_len + 3U) / 4U; + + /* check if there is enough space in fifo space */ + if (dword_len > (pudev->regs.hr->HPTFQSTAT & HPTFQSTAT_PTXFS)) { + /* need to process data in ptxfempty interrupt */ + pudev->regs.gr->GINTEN |= GINTEN_PTXFEIE; + } + break; + + default: + break; + } + + /* write packet into the tx fifo. */ + usb_txfifo_write (&pudev->regs, pp->xfer_buf, pipe_num, pp->xfer_len); + } + } + + return status; +} + +/*! + \brief halt pipe + \param[in] pudev: pointer to usb device + \param[in] pipe_num: host pipe number which is in (0..7) + \param[out] none + \retval operation status +*/ +usb_status usb_pipe_halt (usb_core_driver *pudev, uint8_t pipe_num) +{ + __IO uint32_t pp_ctl = pudev->regs.pr[pipe_num]->HCHCTL; + + uint8_t ep_type = (pp_ctl & HCHCTL_EPTYPE) >> 18U; + + pp_ctl |= HCHCTL_CEN | HCHCTL_CDIS; + + switch (ep_type) { + case USB_EPTYPE_CTRL: + case USB_EPTYPE_BULK: + if (0U == (pudev->regs.gr->HNPTFQSTAT & HNPTFQSTAT_NPTXFS)) { + pp_ctl &= ~HCHCTL_CEN; + } + break; + + case USB_EPTYPE_INTR: + case USB_EPTYPE_ISOC: + if (0U == (pudev->regs.hr->HPTFQSTAT & HPTFQSTAT_PTXFS)) { + pp_ctl &= ~HCHCTL_CEN; + } + break; + + default: + break; + } + + pudev->regs.pr[pipe_num]->HCHCTL = pp_ctl; + + return USB_OK; +} + +/*! + \brief configure host pipe to do ping operation + \param[in] pudev: pointer to usb device + \param[in] pipe_num: host pipe number which is in (0..7) + \param[out] none + \retval operation status +*/ +usb_status usb_pipe_ping (usb_core_driver *pudev, uint8_t pipe_num) +{ + uint32_t pp_ctl = 0U; + + pudev->regs.pr[pipe_num]->HCHLEN = HCHLEN_PING | (HCHLEN_PCNT & (1U << 19U)); + + pp_ctl = pudev->regs.pr[pipe_num]->HCHCTL; + + pp_ctl |= HCHCTL_CEN; + pp_ctl &= ~HCHCTL_CDIS; + + pudev->regs.pr[pipe_num]->HCHCTL = pp_ctl; + + return USB_OK; +} + +/*! + \brief stop the USB host and clean up FIFO + \param[in] none + \param[out] none + \retval none +*/ +void usb_host_stop (usb_core_driver *pudev) +{ + uint32_t i; + __IO uint32_t pp_ctl = 0U; + + pudev->regs.hr->HACHINTEN = 0x0U; + pudev->regs.hr->HACHINT = 0xFFFFFFFFU; + + /* flush out any leftover queued requests. */ + for (i = 0U; i < pudev->bp.num_pipe; i++) { + pp_ctl = pudev->regs.pr[i]->HCHCTL; + + pp_ctl &= ~(HCHCTL_CEN | HCHCTL_EPDIR); + pp_ctl |= HCHCTL_CDIS; + + pudev->regs.pr[i]->HCHCTL = pp_ctl; + } + + /* flush the FIFO */ + usb_rxfifo_flush (&pudev->regs); + usb_txfifo_flush (&pudev->regs, 0x10U); +} diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/drv_usbh_int.c b/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/drv_usbh_int.c new file mode 100644 index 0000000..1b5b6d0 --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/drv_usbh_int.c @@ -0,0 +1,538 @@ +/*! + \file drv_usbh_int.c + \brief USB host mode interrupt handler file + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS + \version 2019-09-25, V1.0.1, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#include "../Include/drv_usb_core.h" +#include "../Include/drv_usb_host.h" +#include "../Include/drv_usbh_int.h" + +#if defined (__GNUC__) /*!< GNU compiler */ + #pragma GCC optimize ("O0") +#endif /* __GNUC__ */ + +static uint32_t usbh_int_port (usb_core_driver *pudev); +static uint32_t usbh_int_pipe (usb_core_driver *pudev); +static uint32_t usbh_int_pipe_in (usb_core_driver *pudev, uint32_t pp_num); +static uint32_t usbh_int_pipe_out (usb_core_driver *pudev, uint32_t pp_num); +static uint32_t usbh_int_rxfifonoempty (usb_core_driver *pudev); +static uint32_t usbh_int_txfifoempty (usb_core_driver *pudev, usb_pipe_mode pp_mode); + +static inline void usb_pp_halt (usb_core_driver *pudev, + uint8_t pp_num, + uint32_t pp_int, + usb_pipe_staus pp_status) +{ + pudev->regs.pr[pp_num]->HCHINTEN |= HCHINTEN_CHIE; + + usb_pipe_halt(pudev, pp_num); + + pudev->regs.pr[pp_num]->HCHINTF = pp_int; + + pudev->host.pipe[pp_num].pp_status = pp_status; +} + +/*! + \brief handle global host interrupt + \param[in] pudev: pointer to usb core instance + \param[out] none + \retval operation status +*/ +uint32_t usbh_isr (usb_core_driver *pudev) +{ + uint32_t Retval = 0U; + + __IO uint32_t intr = 0U; + + /* check if host mode */ + if (HOST_MODE == (pudev->regs.gr->GINTF & GINTF_COPM)) { + intr = usb_coreintr_get(&pudev->regs); + + if (!intr) { + return 0; + } + + if (intr & GINTF_SOF) { + usbh_int_fop->SOF(pudev); + + /* clear interrupt */ + pudev->regs.gr->GINTF = GINTF_SOF; + } + + if (intr & GINTF_RXFNEIF) { + Retval |= usbh_int_rxfifonoempty (pudev); + } + + if (intr & GINTF_NPTXFEIF) { + Retval |= usbh_int_txfifoempty (pudev, PIPE_NON_PERIOD); + } + + if (intr & GINTF_PTXFEIF) { + Retval |= usbh_int_txfifoempty (pudev, PIPE_PERIOD); + } + + if (intr & GINTF_HCIF) { + Retval |= usbh_int_pipe (pudev); + } + + if (intr & GINTF_HPIF) { + Retval |= usbh_int_port (pudev); + } + + if (intr & GINTF_DISCIF) { + pudev->host.connect_status = 0U; + + /* clear interrupt */ + pudev->regs.gr->GINTF = GINTF_DISCIF; + } + + if (intr & GINTF_ISOONCIF) { + pudev->regs.pr[0]->HCHCTL |= HCHCTL_CEN | HCHCTL_CDIS; + + /* clear interrupt */ + pudev->regs.gr->GINTF = GINTF_ISOONCIF; + } + } + + return Retval; +} + +/*! + \brief handle all host channels interrupt + \param[in] pudev: pointer to usb device instance + \param[out] none + \retval operation status +*/ +static uint32_t usbh_int_pipe (usb_core_driver *pudev) +{ + uint32_t pp_num = 0U; + uint32_t retval = 0U; + + for (pp_num = 0U; pp_num < pudev->bp.num_pipe; pp_num++) { + if ((pudev->regs.hr->HACHINT & HACHINT_HACHINT) & (1U << pp_num)) { + if (pudev->regs.pr[pp_num]->HCHCTL & HCHCTL_EPDIR) { + retval |= usbh_int_pipe_in (pudev, pp_num); + } else { + retval |= usbh_int_pipe_out (pudev, pp_num); + } + } + } + + return retval; +} + +/*! + \brief handle the TX FIFO empty interrupt + \param[in] pudev: pointer to usb device instance + \param[out] none + \retval operation status +*/ +static uint32_t usbh_int_txfifoempty (usb_core_driver *pudev, usb_pipe_mode pp_mode) +{ + uint8_t pp_num = 0U; + uint16_t word_count = 0U, len = 0U; + __IO uint32_t *txfiforeg = 0U, txfifostate = 0U; + + if (PIPE_NON_PERIOD == pp_mode) { + txfiforeg = &pudev->regs.gr->HNPTFQSTAT; + } else if (PIPE_PERIOD == pp_mode) { + txfiforeg = &pudev->regs.hr->HPTFQSTAT; + } else { + return 0U; + } + + txfifostate = *txfiforeg; + + pp_num = (txfifostate & TFQSTAT_CNUM) >> 27U; + + word_count = (pudev->host.pipe[pp_num].xfer_len + 3U) / 4U; + + while (((txfifostate & TFQSTAT_TXFS) > word_count) && (0U != pudev->host.pipe[pp_num].xfer_len)) { + len = (txfifostate & TFQSTAT_TXFS) * 4U; + + if (len > pudev->host.pipe[pp_num].xfer_len) { + /* last packet */ + len = pudev->host.pipe[pp_num].xfer_len; + + if (PIPE_NON_PERIOD == pp_mode) { + pudev->regs.gr->GINTEN &= ~GINTEN_NPTXFEIE; + } else { + pudev->regs.gr->GINTEN &= ~GINTEN_PTXFEIE; + } + } + + word_count = (pudev->host.pipe[pp_num].xfer_len + 3U) / 4U; + usb_txfifo_write (&pudev->regs, pudev->host.pipe[pp_num].xfer_buf, pp_num, len); + + pudev->host.pipe[pp_num].xfer_buf += len; + pudev->host.pipe[pp_num].xfer_len -= len; + pudev->host.pipe[pp_num].xfer_count += len; + + txfifostate = *txfiforeg; + } + + return 1; +} + +/*! + \brief handle the host port interrupt + \param[in] pudev: pointer to usb device instance + \param[out] none + \retval operation status +*/ +static uint32_t usbh_int_port (usb_core_driver *pudev) +{ + uint32_t retval = 0U; + + __IO uint32_t port_state = *pudev->regs.HPCS; + + /* clear the interrupt bits in GINTSTS */ + port_state &= ~(HPCS_PE | HPCS_PCD | HPCS_PEDC); + + /* port connect detected */ + if (*pudev->regs.HPCS & HPCS_PCD) { + port_state |= HPCS_PCD; + + pudev->host.connect_status = 1U; + + retval |= 1U; + } + + /* port enable changed */ + if (*pudev->regs.HPCS & HPCS_PEDC) { + port_state |= HPCS_PEDC; + + if (*pudev->regs.HPCS & HPCS_PE) { + uint32_t port_speed = usb_curspeed_get(pudev); + uint32_t clock_type = pudev->regs.hr->HCTL & HCTL_CLKSEL; + + pudev->host.connect_status = 1U; + + if (PORT_SPEED_LOW == port_speed) { + pudev->regs.hr->HFT = 6000U; + + if (HCTL_6MHZ != clock_type) { + if (USB_EMBEDDED_PHY == pudev->bp.phy_itf) { + usb_phyclock_config (pudev, HCTL_6MHZ); + } + } + } else if (PORT_SPEED_FULL == port_speed) { + pudev->regs.hr->HFT = 48000U; + + if (HCTL_48MHZ != clock_type) { + usb_phyclock_config (pudev, HCTL_48MHZ); + } + } else { + /* for high speed device and others */ + } + + pudev->host.port_enabled = 1U; + + pudev->regs.gr->GINTEN |= GINTEN_DISCIE; + } else { + pudev->host.port_enabled = 0U; + } + } + + /* clear port interrupts */ + *pudev->regs.HPCS = port_state; + + return retval; +} + +/*! + \brief handle the OUT channel interrupt + \param[in] pudev: pointer to usb device instance + \param[in] pp_num: host channel number which is in (0..7) + \param[out] none + \retval operation status +*/ +uint32_t usbh_int_pipe_out (usb_core_driver *pudev, uint32_t pp_num) +{ + usb_pr *pp_reg = pudev->regs.pr[pp_num]; + + usb_pipe *pp = &pudev->host.pipe[pp_num]; + + uint32_t intr_pp = pp_reg->HCHINTF & pp_reg->HCHINTEN; + + if (intr_pp & HCHINTF_ACK) { + pp_reg->HCHINTF = HCHINTF_ACK; + } else if (intr_pp & HCHINTF_STALL) { + usb_pp_halt (pudev, pp_num, HCHINTF_STALL, PIPE_STALL); + } else if (intr_pp & HCHINTF_DTER) { + usb_pp_halt (pudev, pp_num, HCHINTF_DTER, PIPE_DTGERR); + pp_reg->HCHINTF = HCHINTF_NAK; + } else if (intr_pp & HCHINTF_REQOVR) { + usb_pp_halt (pudev, pp_num, HCHINTF_REQOVR, PIPE_REQOVR); + } else if (intr_pp & HCHINTF_TF) { + pp->err_count = 0U; + usb_pp_halt (pudev, pp_num, HCHINTF_TF, PIPE_XF); + } else if (intr_pp & HCHINTF_NAK) { + pp->err_count = 0U; + usb_pp_halt (pudev, pp_num, HCHINTF_NAK, PIPE_NAK); + } else if (intr_pp & HCHINTF_USBER) { + pp->err_count++; + usb_pp_halt (pudev, pp_num, HCHINTF_USBER, PIPE_TRACERR); + } else if (intr_pp & HCHINTF_NYET) { + pp->err_count = 0U; + usb_pp_halt (pudev, pp_num, HCHINTF_NYET, PIPE_NYET); + } else if (intr_pp & HCHINTF_CH) { + pudev->regs.pr[pp_num]->HCHINTEN &= ~HCHINTEN_CHIE; + + switch (pp->pp_status) { + case PIPE_XF: + pp->urb_state = URB_DONE; + + if (USB_EPTYPE_BULK == ((pp_reg->HCHCTL & HCHCTL_EPTYPE) >> 18U)) { + pp->data_toggle_out ^= 1U; + } + break; + + case PIPE_NAK: + pp->urb_state = URB_NOTREADY; + break; + + case PIPE_NYET: + if (1U == pudev->host.pipe[pp_num].ping) { + usb_pipe_ping (pudev, pp_num); + } + + pp->urb_state = URB_NOTREADY; + break; + + case PIPE_STALL: + pp->urb_state = URB_STALL; + break; + + case PIPE_TRACERR: + if (3U == pp->err_count) { + pp->urb_state = URB_ERROR; + pp->err_count = 0U; + } + break; + + default: + break; + } + + pp_reg->HCHINTF = HCHINTF_CH; + } + + return 1; +} + +/*! + \brief handle the IN channel interrupt + \param[in] pudev: pointer to usb device instance + \param[in] pp_num: host channel number which is in (0..7) + \param[out] none + \retval operation status +*/ +uint32_t usbh_int_pipe_in (usb_core_driver *pudev, uint32_t pp_num) +{ + usb_pr *pp_reg = pudev->regs.pr[pp_num]; + + usb_pipe *pp = &pudev->host.pipe[pp_num]; + + __IO uint32_t intr_pp = pp_reg->HCHINTF & pp_reg->HCHINTEN; + + uint8_t ep_type = (pp_reg->HCHCTL & HCHCTL_EPTYPE) >> 18U; + + if (intr_pp & HCHINTF_ACK) { + pp_reg->HCHINTF = HCHINTF_ACK; + } else if (intr_pp & HCHINTF_STALL) { + usb_pp_halt (pudev, pp_num, HCHINTF_STALL, PIPE_STALL); + pp_reg->HCHINTF = HCHINTF_NAK; + + /* note: When there is a 'STALL', reset also nak, + else, the pudev->host.pp_status = HC_STALL + will be overwritten by 'NAK' in code below */ + intr_pp &= ~HCHINTF_NAK; + } else if (intr_pp & HCHINTF_DTER) { + usb_pp_halt (pudev, pp_num, HCHINTF_DTER, PIPE_DTGERR); + pp_reg->HCHINTF = HCHINTF_NAK; + } + + if (intr_pp & HCHINTF_REQOVR) { + usb_pp_halt (pudev, pp_num, HCHINTF_REQOVR, PIPE_REQOVR); + } else if (intr_pp & HCHINTF_TF) { + if (USB_USE_DMA == pudev->bp.transfer_mode) { + pudev->host.backup_xfercount[pp_num] = pp->xfer_len - pp_reg->HCHLEN & HCHLEN_TLEN; + } + + pp->pp_status = PIPE_XF; + pp->err_count = 0U; + + pp_reg->HCHINTF = HCHINTF_TF; + + switch (ep_type) { + case USB_EPTYPE_CTRL: + case USB_EPTYPE_BULK: + usb_pp_halt (pudev, pp_num, HCHINTF_NAK, PIPE_XF); + + pp->data_toggle_in ^= 1U; + break; + + case USB_EPTYPE_INTR: + pp_reg->HCHCTL |= HCHCTL_ODDFRM; + pp->urb_state = URB_DONE; + break; + + default: + break; + } + } else if (intr_pp & HCHINTF_CH) { + pp_reg->HCHINTEN &= ~HCHINTEN_CHIE; + + switch (pp->pp_status) { + case PIPE_XF: + pp->urb_state = URB_DONE; + break; + + case PIPE_STALL: + pp->urb_state = URB_STALL; + break; + + case PIPE_TRACERR: + case PIPE_DTGERR: + pp->err_count = 0U; + pp->urb_state = URB_ERROR; + pp->data_toggle_in ^= 1U; + break; + + default: + if(USB_EPTYPE_INTR == ep_type) { + pp->data_toggle_in ^= 1U; + } + break; + } + + pp_reg->HCHINTF = HCHINTF_CH; + } else if (intr_pp & HCHINTF_USBER) { + pp->err_count++; + usb_pp_halt (pudev, pp_num, HCHINTF_USBER, PIPE_TRACERR); + } else if (intr_pp & HCHINTF_NAK) { + switch (ep_type) { + case USB_EPTYPE_CTRL: + case USB_EPTYPE_BULK: + /* re-activate the channel */ + pp_reg->HCHCTL = (pp_reg->HCHCTL | HCHCTL_CEN) & ~HCHCTL_CDIS; + break; + + case USB_EPTYPE_INTR: + pp_reg->HCHINTEN |= HCHINTEN_CHIE; + + usb_pipe_halt(pudev, pp_num); + break; + + default: + break; + } + + pp->pp_status = PIPE_NAK; + + pp_reg->HCHINTF = HCHINTF_NAK; + } + + return 1; +} + +/*! + \brief handle the rx fifo non-empty interrupt + \param[in] pudev: pointer to usb device instance + \param[out] none + \retval operation status +*/ +static uint32_t usbh_int_rxfifonoempty (usb_core_driver *pudev) +{ + uint32_t count = 0U; + + __IO uint8_t pp_num = 0U; + __IO uint32_t rx_stat = 0U; + + /* disable the rx status queue level interrupt */ + pudev->regs.gr->GINTEN &= ~GINTEN_RXFNEIE; + + rx_stat = pudev->regs.gr->GRSTATP; + pp_num = rx_stat & GRSTATRP_CNUM; + + switch ((rx_stat & GRSTATRP_RPCKST) >> 17U) { + case GRXSTS_PKTSTS_IN: + count = (rx_stat & GRSTATRP_BCOUNT) >> 4U; + + /* read the data into the host buffer. */ + if ((count > 0U) && (NULL != pudev->host.pipe[pp_num].xfer_buf)) { + usb_rxfifo_read (&pudev->regs, pudev->host.pipe[pp_num].xfer_buf, count); + + /* manage multiple transfer packet */ + pudev->host.pipe[pp_num].xfer_buf += count; + pudev->host.pipe[pp_num].xfer_count += count; + + pudev->host.backup_xfercount[pp_num] = pudev->host.pipe[pp_num].xfer_count; + + if (pudev->regs.pr[pp_num]->HCHLEN & HCHLEN_PCNT) { + /* re-activate the channel when more packets are expected */ + __IO uint32_t pp_ctl = pudev->regs.pr[pp_num]->HCHCTL; + + pp_ctl |= HCHCTL_CEN; + pp_ctl &= ~HCHCTL_CDIS; + + pudev->regs.pr[pp_num]->HCHCTL = pp_ctl; + } + } + break; + + case GRXSTS_PKTSTS_IN_XFER_COMP: + break; + + case GRXSTS_PKTSTS_DATA_TOGGLE_ERR: + count = (rx_stat & GRSTATRP_BCOUNT) >> 4U; + + while (count > 0U) { + rx_stat = pudev->regs.gr->GRSTATP; + count--; + } + break; + + case GRXSTS_PKTSTS_CH_HALTED: + break; + + default: + break; + } + + /* enable the rx status queue level interrupt */ + pudev->regs.gr->GINTEN |= GINTEN_RXFNEIE; + + return 1; +} diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/usbh_core.c b/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/usbh_core.c new file mode 100644 index 0000000..fd7d13d --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/usbh_core.c @@ -0,0 +1,465 @@ +/*! + \file usbh_core.c + \brief USB host core state machine driver + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#include "../Include/drv_usb_hw.h" +#include "../Include/usbh_pipe.h" +#include "../Include/usbh_enum.h" +#include "../Include/usbh_core.h" +#include "../Include/drv_usbh_int.h" + +uint8_t usbh_sof (usb_core_driver *pudev); + +usbh_int_cb usbh_int_op = +{ + usbh_sof +}; + +usbh_int_cb *usbh_int_fop = &usbh_int_op; + +static usbh_status usbh_enum_task (usb_core_driver *pudev, usbh_host *puhost); + +/*! + \brief USB SOF callback function from the interrupt + \param[in] pudev: pointer to usb core instance + \param[out] none + \retval operation status +*/ +uint8_t usbh_sof (usb_core_driver *pudev) +{ + /* this callback could be used to implement a scheduler process */ + return 0U; +} + +/*! + \brief USB host stack initializations + \param[in] pudev: pointer to usb core instance + \param[in] core: USBFS core or USBHS core + \param[in] puhost: pointer to USB host + \param[out] none + \retval operation status +*/ +void usbh_init (usb_core_driver *pudev, usb_core_enum core, usbh_host *puhost,void (*pUsrFunc)(usbh_host *phost, uint8_t )) +{ + uint8_t i = 0U; + + /* host de-initializations */ + usbh_deinit(pudev, puhost); + + pudev->host.connect_status = 0U; + + for (i = 0U; i < USBFS_MAX_TX_FIFOS; i++) { + pudev->host.pipe[i].err_count = 0U; + pudev->host.pipe[i].pp_status = PIPE_IDLE; + pudev->host.backup_xfercount[i] = 0U; + } + + pudev->host.pipe[0].ep.mps = 8U; + + usb_basic_init (&pudev->bp, &pudev->regs, core); + +#ifndef DUAL_ROLE_MODE_ENABLED + + usb_core_init (pudev->bp, &pudev->regs); + + usb_host_init (pudev); + +#endif /* DUAL_ROLE_MODE_ENABLED */ + + /* upon init call usr call back */ + puhost->usr_cb->dev_init(); + if(pUsrFunc != NULL) + { + puhost->pUser= pUsrFunc; + } +} + +/*! + \brief de-initialize USB host + \param[in] pudev: pointer to usb core instance + \param[in] puhost: pointer to USB host + \param[out] none + \retval operation status +*/ +usbh_status usbh_deinit(usb_core_driver *pudev, usbh_host *puhost) +{ + /* software init */ + puhost->cur_state = HOST_DEFAULT; + puhost->backup_state = HOST_DEFAULT; + puhost->enum_state = ENUM_DEFAULT; + + puhost->control.ctl_state = CTL_IDLE; + puhost->control.max_len = USB_FS_EP0_MAX_LEN; + + puhost->dev_prop.addr = USBH_DEV_ADDR_DEFAULT; + puhost->dev_prop.speed = PORT_SPEED_FULL; + + usbh_pipe_free(pudev, puhost->control.pipe_in_num); + usbh_pipe_free(pudev, puhost->control.pipe_out_num); + + return USBH_OK; +} + +/*! + \brief USB host core main state machine process + \param[in] pudev: pointer to usb core instance + \param[in] puhost: pointer to USB host + \param[out] none + \retval none +*/ +void usbh_core_task (usb_core_driver *pudev, usbh_host *puhost) +{ + volatile usbh_status status = USBH_FAIL; + + /* check for host port events */ + if (((0U == pudev->host.connect_status) || (0U == pudev->host.port_enabled)) && (HOST_DEFAULT != puhost->cur_state)) { + if (puhost->cur_state != HOST_DEV_DETACHED) { + puhost->cur_state = HOST_DEV_DETACHED; + } + } + + switch (puhost->cur_state) { + case HOST_DEFAULT: + if (pudev->host.connect_status) { + puhost->cur_state = HOST_DETECT_DEV_SPEED; + + usb_mdelay (200U); + // usb_mdelay (2U); + usb_port_reset (pudev); + + //puhost->usr_cb->dev_reset(); + } + break; + + case HOST_DETECT_DEV_SPEED: + if (pudev->host.port_enabled) { + puhost->cur_state = HOST_DEV_ATTACHED; + puhost->dev_prop.speed = usb_curspeed_get (pudev); + //puhost->usr_cb->dev_speed_detected(puhost->dev_prop.speed); + + usb_mdelay (100U); + } + break; + + case HOST_DEV_ATTACHED: + //puhost->usr_cb->dev_attach(); + puhost->control.pipe_out_num = usbh_pipe_allocate(pudev, 0x00U); + puhost->control.pipe_in_num = usbh_pipe_allocate(pudev, 0x80U); + + /* reset USB device */ + usb_port_reset (pudev); + + /* open IN control pipe */ + usbh_pipe_create (pudev, + &puhost->dev_prop, + puhost->control.pipe_in_num, + USB_EPTYPE_CTRL, + puhost->control.max_len); + + /* open OUT control pipe */ + usbh_pipe_create (pudev, + &puhost->dev_prop, + puhost->control.pipe_out_num, + USB_EPTYPE_CTRL, + puhost->control.max_len); + + puhost->cur_state = HOST_ENUM; + break; + + case HOST_ENUM: + + /* check for enumeration status */ + if (USBH_OK == usbh_enum_task (pudev, puhost)) { + /* the function shall return USBH_OK when full enumeration is complete */ + + /* user callback for end of device basic enumeration */ + //puhost->usr_cb->dev_enumerated(); + puhost->cur_state = HOST_USER_INPUT; + } + break; + + case HOST_USER_INPUT: + /* the function should return user response true to move to class state */ + /*if (USBH_USER_RESP_OK == puhost->usr_cb->dev_user_input()) { + if ((USBH_OK == puhost->class_cb->class_init(pudev, puhost))) { + puhost->cur_state = HOST_CLASS_ENUM; + } + }*/ + if(puhost->pUser != NULL) + { + puhost->pUser(puhost, HOST_USER_SELECT_CONFIGURATION); + puhost->cur_state = HOST_CHECK_CLASS; + } + break; + case HOST_CHECK_CLASS: + puhost->cur_state = HOST_CLASS_ENUM; + //USBH_UsrLog ("%s class started.", phost->pActiveClass->Name); + + /* Inform user that a class has been activated */ + puhost->pUser(puhost, HOST_USER_CLASS_SELECTED); + + puhost->pUser(puhost, HOST_USER_CLASS_FAILED); + puhost->cur_state = HOST_ERROR; + //USBH_UsrLog ("Device not supporting %s class.", phost->pActiveClass->Name); + + puhost->pUser(puhost, HOST_USER_CLASS_FAILED); + puhost->cur_state = HOST_ERROR; + //USBH_UsrLog ("No registered class for this device."); + break; + case HOST_CLASS_ENUM: + /* process class standard contol requests state machine */ + status = puhost->class_cb->class_requests(pudev, puhost); + + if (USBH_OK == status) { + puhost->cur_state = HOST_CLASS_HANDLER; + } else { + puhost->cur_state = HOST_ERROR; + usbh_error_handler (puhost, status); + } + break; + + case HOST_CLASS_HANDLER: + /* process class state machine */ + status = puhost->class_cb->class_machine(pudev, puhost); + puhost->cur_state = HOST_ERROR; + usbh_error_handler (puhost, status); + break; + + case HOST_SUSPENDED: + break; + + case HOST_ERROR: + /* re-initilaize host for new enumeration */ + usbh_deinit (pudev, puhost); + puhost->usr_cb->dev_deinit(); + puhost->class_cb->class_deinit(pudev, puhost); + break; + + case HOST_DEV_DETACHED: + /* manage user disconnect operations*/ + puhost->usr_cb->dev_detach(); + + /* re-initilaize host for new enumeration */ + usbh_deinit(pudev, puhost); + puhost->usr_cb->dev_deinit(); + puhost->class_cb->class_deinit(pudev, puhost); + usbh_pipe_delete(pudev); + puhost->cur_state = HOST_DEFAULT; + break; + + default: + break; + } +} + +/*! + \brief handle the error on USB host side + \param[in] puhost: pointer to USB host + \param[in] err_type: type of error or busy/OK state + \param[out] none + \retval none +*/ +void usbh_error_handler (usbh_host *puhost, usbh_status err_type) +{ + /* error unrecovered or not supported device speed */ + if ((USBH_SPEED_UNKNOWN_ERROR == err_type) || (USBH_UNRECOVERED_ERROR == err_type)) { + puhost->usr_cb->dev_error(); + + puhost->cur_state = HOST_ERROR; + } else if (USBH_APPLY_DEINIT == err_type) { + puhost->cur_state = HOST_ERROR; + + /* user callback for initalization */ + puhost->usr_cb->dev_init(); + } +} + +/*! + \brief handle the USB enumeration task + \param[in] pudev: pointer to selected USB device + \param[in] puhost: pointer to host + \param[out] none + \retval none +*/ +static usbh_status usbh_enum_task (usb_core_driver *pudev, usbh_host *puhost) +{ + uint8_t str_buf[64]; + + usbh_status status = USBH_BUSY; + + static uint8_t index_mfc_str = 0U, index_prod_str = 0U, index_serial_str = 0U; + + switch (puhost->enum_state) { + case ENUM_DEFAULT: + /* get device descriptor for only 1st 8 bytes : to get ep0 maxpacketsize */ + if (USBH_OK == usbh_devdesc_get (pudev, puhost, 8U)) { + + puhost->control.max_len = puhost->dev_prop.dev_desc.bMaxPacketSize0; + + /* issue reset */ + usb_port_reset (pudev); + + /* modify control channels configuration for maximum packet size */ + usbh_pipe_update (pudev, + puhost->control.pipe_out_num, + 0U, 0U, + puhost->control.max_len); + + usbh_pipe_update (pudev, + puhost->control.pipe_in_num, + 0U, 0U, + puhost->control.max_len); + + puhost->enum_state = ENUM_GET_DEV_DESC; + + } + break; + + case ENUM_GET_DEV_DESC: + /* get full device descriptor */ + if (USBH_OK == usbh_devdesc_get (pudev, puhost, USB_DEV_DESC_LEN)) { + puhost->usr_cb->dev_devdesc_assigned(&puhost->dev_prop.dev_desc); + + index_mfc_str = puhost->dev_prop.dev_desc.iManufacturer; + index_prod_str = puhost->dev_prop.dev_desc.iProduct; + index_serial_str = puhost->dev_prop.dev_desc.iSerialNumber; + + puhost->enum_state = ENUM_SET_ADDR; + } + break; + + case ENUM_SET_ADDR: + /* set address */ + if (USBH_OK == usbh_setaddress (pudev, puhost, USBH_DEV_ADDR)) { + usb_mdelay (2); + + puhost->dev_prop.addr = USBH_DEV_ADDR; + + /* user callback for device address assigned */ + puhost->usr_cb->dev_address_set(); + + /* modify control channels to update device address */ + usbh_pipe_update (pudev, + puhost->control.pipe_in_num, + puhost->dev_prop.addr, + 0U, 0U); + + usbh_pipe_update (pudev, + puhost->control.pipe_out_num, + puhost->dev_prop.addr, + 0U, 0U); + + puhost->enum_state = ENUM_GET_CFG_DESC; + } + break; + + case ENUM_GET_CFG_DESC: + /* get standard configuration descriptor */ + if (USBH_OK == usbh_cfgdesc_get (pudev, puhost, USB_CFG_DESC_LEN)) { + puhost->enum_state = ENUM_GET_CFG_DESC_SET; + } + break; + + case ENUM_GET_CFG_DESC_SET: + /* get full config descriptor (config, interface, endpoints) */ + if (USBH_OK == usbh_cfgdesc_get (pudev, puhost, puhost->dev_prop.cfg_desc.wTotalLength)) { + /* user callback for configuration descriptors available */ + puhost->usr_cb->dev_cfgdesc_assigned (&puhost->dev_prop.cfg_desc, + puhost->dev_prop.itf_desc, + puhost->dev_prop.ep_desc[0]); + + puhost->enum_state = ENUM_GET_STR_DESC; + } + break; + + case ENUM_GET_STR_DESC: + if (index_mfc_str) { + if (USBH_OK == usbh_strdesc_get (pudev, + puhost, + puhost->dev_prop.dev_desc.iManufacturer, + str_buf, + 0xFFU)) { + /* user callback for manufacturing string */ + puhost->usr_cb->dev_mfc_str(str_buf); + + index_mfc_str = 0U; + } + } else { + if (index_prod_str) { + /* check that product string is available */ + if (USBH_OK == usbh_strdesc_get (pudev, + puhost, + puhost->dev_prop.dev_desc.iProduct, + str_buf, + 0xFFU)) { + puhost->usr_cb->dev_prod_str(str_buf); + + index_prod_str = 0U; + } + } else { + if (index_serial_str) { + if (USBH_OK == usbh_strdesc_get (pudev, + puhost, + puhost->dev_prop.dev_desc.iSerialNumber, + str_buf, + 0xFFU)) { + puhost->usr_cb->dev_seral_str(str_buf); + puhost->enum_state = ENUM_SET_CONFIGURATION; + + index_serial_str = 0U; + } + } else { + puhost->enum_state = ENUM_SET_CONFIGURATION; + } + } + } + break; + + case ENUM_SET_CONFIGURATION: + if (USBH_OK == usbh_setcfg (pudev, + puhost, + puhost->dev_prop.cfg_desc.bConfigurationValue)) { + puhost->enum_state = ENUM_DEV_CONFIGURED; + } + break; + + case ENUM_DEV_CONFIGURED: + status = USBH_OK; + break; + + default: + break; + } + + return status; +} diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/usbh_enum.c b/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/usbh_enum.c new file mode 100644 index 0000000..fe41560 --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/usbh_enum.c @@ -0,0 +1,549 @@ +/*! + \file usbh_enum.c + \brief USB host mode enumberation driver + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#include "../Include/usbh_transc.h" +#include "../Include/usbh_enum.h" + +static void usbh_devdesc_parse (usb_desc_dev *cfg_desc, uint8_t *buf, uint16_t len); +static void usbh_cfgset_parse (usb_dev_prop *udev, uint8_t *buf); +static void usbh_cfgdesc_parse (usb_desc_config *cfg_desc, uint8_t *buf); +static void usbh_itfdesc_parse (usb_desc_itf *itf_desc, uint8_t *buf); +static void usbh_epdesc_parse (usb_desc_ep *ep_desc, uint8_t *buf); +static void usbh_strdesc_parse (uint8_t *psrc, uint8_t *pdest, uint16_t len); + + +/*! + \brief configure USB control status parameters + \param[in] puhost: pointer to usb host + \param[in] buf: control transfer data buffer pointer + \param[in] len: length of the data buffer + \param[out] none + \retval none +*/ +void usbh_ctlstate_config (usbh_host *puhost, uint8_t *buf, uint16_t len) +{ + /* prepare the transactions */ + puhost->control.buf = buf; + puhost->control.ctl_len = len; + + puhost->control.ctl_state = CTL_SETUP; +} + +/*! + \brief get device descriptor from the USB device + \param[in] pudev: pointer to usb core instance + \param[in] puhost: pointer to usb host + \param[in] len: length of the descriptor + \param[out] none + \retval operation status +*/ +usbh_status usbh_devdesc_get (usb_core_driver *pudev, usbh_host *puhost, uint8_t len) +{ + usbh_status status = USBH_BUSY; + + usbh_control *usb_ctl = &puhost->control; + + if (CTL_IDLE == usb_ctl->ctl_state) { + usb_ctl->setup.req = (usb_req) { + .bmRequestType = USB_TRX_IN | USB_RECPTYPE_DEV | USB_REQTYPE_STRD, + .bRequest = USB_GET_DESCRIPTOR, + .wValue = USBH_DESC(USB_DESCTYPE_DEV), + .wIndex = 0U, + .wLength = len + }; + + usbh_ctlstate_config (puhost, pudev->host.rx_buf, len); + } + + status = usbh_ctl_handler (pudev, puhost); + + if (USBH_OK == status) { + /* commands successfully sent and response received */ + usbh_devdesc_parse (&puhost->dev_prop.dev_desc, pudev->host.rx_buf, len); + } + + return status; +} + +/*! + \brief get configuration descriptor from the USB device + \param[in] pudev: pointer to usb core instance + \param[in] puhost: pointer to usb host + \param[in] len: length of the descriptor + \param[out] none + \retval operation status +*/ +usbh_status usbh_cfgdesc_get (usb_core_driver *pudev, usbh_host *puhost, uint16_t len) +{ + usbh_status status = USBH_BUSY; + + usbh_control *usb_ctl = &puhost->control; + + if (CTL_IDLE == usb_ctl->ctl_state) { + usb_ctl->setup.req = (usb_req) { + .bmRequestType = USB_TRX_IN | USB_RECPTYPE_DEV | USB_REQTYPE_STRD, + .bRequest = USB_GET_DESCRIPTOR, + .wValue = USBH_DESC(USB_DESCTYPE_CONFIG), + .wIndex = 0U, + .wLength = len + }; + + usbh_ctlstate_config (puhost, pudev->host.rx_buf, len); + } + + status = usbh_ctl_handler (pudev, puhost); + + if (USBH_OK == status) { + if (len <= USB_CFG_DESC_LEN) { + usbh_cfgdesc_parse (&puhost->dev_prop.cfg_desc, pudev->host.rx_buf); + } else { + usbh_cfgset_parse (&puhost->dev_prop, pudev->host.rx_buf); + } + } + + return status; +} + +/*! + \brief get string descriptor from the USB device + \param[in] pudev: pointer to usb core instance + \param[in] puhost: pointer to usb host + \param[in] str_index: index for the string descriptor + \param[in] buf: buffer pointer to the string descriptor + \param[in] len: length of the descriptor + \param[out] none + \retval operation status +*/ +usbh_status usbh_strdesc_get (usb_core_driver *pudev, + usbh_host *puhost, + uint8_t str_index, + uint8_t *buf, + uint16_t len) +{ + usbh_status status = USBH_BUSY; + + usbh_control *usb_ctl = &puhost->control; + + if (CTL_IDLE == usb_ctl->ctl_state) { + usb_ctl->setup.req = (usb_req) { + .bmRequestType = USB_TRX_IN | USB_RECPTYPE_DEV | USB_REQTYPE_STRD, + .bRequest = USB_GET_DESCRIPTOR, + .wValue = USBH_DESC(USB_DESCTYPE_STR) | str_index, + .wIndex = 0x0409U, + .wLength = len + }; + + usbh_ctlstate_config (puhost, pudev->host.rx_buf, len); + } + + status = usbh_ctl_handler (pudev, puhost); + + if (USBH_OK == status) { + /* commands successfully sent and response received */ + usbh_strdesc_parse (pudev->host.rx_buf, buf, len); + } + + return status; +} + +/*! + \brief set the address to the connected device + \param[in] pudev: pointer to usb core instance + \param[in] puhost: pointer to usb host + \param[in] dev_addr: device address to assign + \param[out] none + \retval operation status +*/ +usbh_status usbh_setaddress (usb_core_driver *pudev, usbh_host *puhost, uint8_t dev_addr) +{ + usbh_status status = USBH_BUSY; + + usbh_control *usb_ctl = &puhost->control; + + if (CTL_IDLE == usb_ctl->ctl_state) { + usb_ctl->setup.req = (usb_req) { + .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_DEV | USB_REQTYPE_STRD, + .bRequest = USB_SET_ADDRESS, + .wValue = (uint16_t)dev_addr, + .wIndex = 0U, + .wLength = 0U + }; + + usbh_ctlstate_config (puhost, NULL, 0U); + } + + status = usbh_ctl_handler (pudev, puhost); + + return status; +} + +/*! + \brief set the configuration value to the connected device + \param[in] pudev: pointer to usb core instance + \param[in] puhost: pointer to usb host + \param[in] config_index: configuration value + \param[out] none + \retval operation status +*/ +usbh_status usbh_setcfg (usb_core_driver *pudev, usbh_host *puhost, uint16_t config_index) +{ + usbh_status status = USBH_BUSY; + + usbh_control *usb_ctl = &puhost->control; + + if (CTL_IDLE == usb_ctl->ctl_state) { + usb_ctl->setup.req = (usb_req) { + .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_DEV | USB_REQTYPE_STRD, + .bRequest = USB_SET_CONFIGURATION, + .wValue = config_index, + .wIndex = 0U, + .wLength = 0U + }; + + usbh_ctlstate_config (puhost, NULL, 0U); + } + + status = usbh_ctl_handler (pudev, puhost); + + return status; +} + +/*! + \brief set the interface value to the connected device + \param[in] pudev: pointer to usb core instance + \param[in] puhost: pointer to usb host + \param[in] ep_num: endpoint number + \param[in] alter_setting: altnated setting value + \param[out] none + \retval operation status +*/ +usbh_status usbh_setinterface (usb_core_driver *pudev, + usbh_host *puhost, + uint8_t ep_num, + uint8_t set) +{ + usbh_status status = USBH_BUSY; + + usbh_control *usb_ctl = &puhost->control; + + if (CTL_IDLE == usb_ctl->ctl_state) { + usb_ctl->setup.req = (usb_req) { + .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_ITF | USB_REQTYPE_STRD, + .bRequest = USB_SET_INTERFACE, + .wValue = set, + .wIndex = ep_num, + .wLength = 0U + }; + + usbh_ctlstate_config (puhost, NULL, 0U); + } + + status = usbh_ctl_handler (pudev, puhost); + + return status; +} + +/*! + \brief clear or disable a specific feature + \param[in] pudev: pointer to usb core instance + \param[in] puhost: pointer to usb host + \param[in] ep_addr: endpoint address + \param[in] pp_num: pipe number + \param[out] none + \retval operation status +*/ +usbh_status usbh_clrfeature (usb_core_driver *pudev, + usbh_host *puhost, + uint8_t ep_addr, + uint8_t pp_num) +{ + usbh_status status = USBH_BUSY; + + usbh_control *usb_ctl = &puhost->control; + + if (CTL_IDLE == usb_ctl->ctl_state) { + usb_ctl->setup.req = (usb_req) { + .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_EP | USB_REQTYPE_STRD, + .bRequest = USB_CLEAR_FEATURE, + .wValue = FEATURE_SELECTOR_EP, + .wIndex = ep_addr, + .wLength = 0 + }; + + if (EP_DIR(ep_addr)) { + pudev->host.pipe[pp_num].data_toggle_in = 0U; + } else { + pudev->host.pipe[pp_num].data_toggle_out = 0U; + } + + usbh_ctlstate_config (puhost, NULL, 0U); + } + + status = usbh_ctl_handler (pudev, puhost); + + return status; +} + +/*! + \brief parse the device descriptor + \param[in] dev_desc: pointer to usb device descriptor buffer + \param[in] buf: pointer to the source descriptor buffer + \param[in] len: length of the descriptor + \param[out] none + \retval operation status +*/ +static void usbh_devdesc_parse (usb_desc_dev *dev_desc, uint8_t *buf, uint16_t len) +{ + *dev_desc = (usb_desc_dev) { + .header = { + .bLength = *(uint8_t *)(buf + 0U), + .bDescriptorType = *(uint8_t *)(buf + 1U) + }, + + .bcdUSB = BYTE_SWAP(buf + 2U), + .bDeviceClass = *(uint8_t *)(buf + 4U), + .bDeviceSubClass = *(uint8_t *)(buf + 5U), + .bDeviceProtocol = *(uint8_t *)(buf + 6U), + .bMaxPacketSize0 = *(uint8_t *)(buf + 7U) + }; + + if (len > 8U) { + /* for 1st time after device connection, host may issue only 8 bytes for device descriptor length */ + dev_desc->idVendor = BYTE_SWAP(buf + 8U); + dev_desc->idProduct = BYTE_SWAP(buf + 10U); + dev_desc->bcdDevice = BYTE_SWAP(buf + 12U); + dev_desc->iManufacturer = *(uint8_t *)(buf + 14U); + dev_desc->iProduct = *(uint8_t *)(buf + 15U); + dev_desc->iSerialNumber = *(uint8_t *)(buf + 16U); + dev_desc->bNumberConfigurations = *(uint8_t *)(buf + 17U); + } +} + +/*! + \brief parse the configuration descriptor + \param[in] cfg_desc: pointer to usb configuration descriptor buffer + \param[in] buf: pointer to the source descriptor buffer + \param[out] none + \retval operation status +*/ +static void usbh_cfgdesc_parse (usb_desc_config *cfg_desc, uint8_t *buf) +{ + /* parse configuration descriptor */ + *cfg_desc = (usb_desc_config) { + .header = { + .bLength = *(uint8_t *)(buf + 0U), + .bDescriptorType = *(uint8_t *)(buf + 1U), + }, + + .wTotalLength = BYTE_SWAP(buf + 2U), + .bNumInterfaces = *(uint8_t *)(buf + 4U), + .bConfigurationValue = *(uint8_t *)(buf + 5U), + .iConfiguration = *(uint8_t *)(buf + 6U), + .bmAttributes = *(uint8_t *)(buf + 7U), + .bMaxPower = *(uint8_t *)(buf + 8U) + }; +} + +/*! + \brief parse the configuration descriptor set + \param[in] udev: pointer to USB core instance + \param[in] buf: pointer to the source descriptor buffer + \param[out] none + \retval operation status +*/ +static void usbh_cfgset_parse (usb_dev_prop *udev, uint8_t *buf) +{ + usb_desc_ep *ep = NULL; + usb_desc_itf *itf = NULL, itf_value; + + usb_desc_header *pdesc = (usb_desc_header *)buf; + + int8_t itf_index = 0U, ep_index = 0U; + uint16_t ptr; + + uint8_t prev_itf = 0U; + uint16_t prev_ep_len = 0U; + + /* parse configuration descriptor */ + usbh_cfgdesc_parse (&udev->cfg_desc, buf); + + ptr = USB_CFG_DESC_LEN; + + if (udev->cfg_desc.bNumInterfaces > USBH_MAX_INTERFACES_NUM) { + return; + } + + while (ptr < udev->cfg_desc.wTotalLength) { + pdesc = usbh_nextdesc_get ((uint8_t *)pdesc, &ptr); + + if (pdesc->bDescriptorType == USB_DESCTYPE_ITF) { + itf_index = *(((uint8_t *)pdesc) + 2U); + itf = &udev->itf_desc[itf_index]; + + if ((*((uint8_t *)pdesc + 3U)) < 3U) { + usbh_itfdesc_parse (&itf_value, (uint8_t *)pdesc); + + /* parse endpoint descriptors relative to the current interface */ + if (itf_value.bNumEndpoints > USBH_MAX_EP_NUM) { + return; + } + + for (ep_index = 0; ep_index < itf_value.bNumEndpoints; ) { + pdesc = usbh_nextdesc_get ((void*)pdesc, &ptr); + + if (pdesc->bDescriptorType == USB_DESCTYPE_EP) { + ep = &udev->ep_desc[itf_index][ep_index]; + + if (prev_itf != itf_index) { + prev_itf = itf_index; + usbh_itfdesc_parse (itf, (uint8_t *)&itf_value); + } else { + if (prev_ep_len > BYTE_SWAP((uint8_t *)pdesc + 4U)) { + break; + } else { + usbh_itfdesc_parse (itf, (uint8_t *)&itf_value); + } + } + + usbh_epdesc_parse (ep, (uint8_t *)pdesc); + prev_ep_len = BYTE_SWAP((uint8_t *)pdesc + 4U); + ep_index++; + } + } + } + } + } +} + +/*! + \brief parse the interface descriptor + \param[in] itf_desc: pointer to usb interface descriptor buffer + \param[in] buf: pointer to the source descriptor buffer + \param[out] none + \retval operation status +*/ +static void usbh_itfdesc_parse (usb_desc_itf *itf_desc, uint8_t *buf) +{ + *itf_desc = (usb_desc_itf) { + .header = { + .bLength = *(uint8_t *)(buf + 0U), + .bDescriptorType = *(uint8_t *)(buf + 1U), + }, + + .bInterfaceNumber = *(uint8_t *)(buf + 2U), + .bAlternateSetting = *(uint8_t *)(buf + 3U), + .bNumEndpoints = *(uint8_t *)(buf + 4U), + .bInterfaceClass = *(uint8_t *)(buf + 5U), + .bInterfaceSubClass = *(uint8_t *)(buf + 6U), + .bInterfaceProtocol = *(uint8_t *)(buf + 7U), + .iInterface = *(uint8_t *)(buf + 8U) + }; +} + +/*! + \brief parse the endpoint descriptor + \param[in] ep_desc: pointer to usb endpoint descriptor buffer + \param[in] buf: pointer to the source descriptor buffer + \param[out] none + \retval operation status +*/ +static void usbh_epdesc_parse (usb_desc_ep *ep_desc, uint8_t *buf) +{ + *ep_desc = (usb_desc_ep) { + .header = { + .bLength = *(uint8_t *)(buf + 0U), + .bDescriptorType = *(uint8_t *)(buf + 1U) + }, + + .bEndpointAddress = *(uint8_t *)(buf + 2U), + .bmAttributes = *(uint8_t *)(buf + 3U), + .wMaxPacketSize = BYTE_SWAP(buf + 4U), + .bInterval = *(uint8_t *)(buf + 6U) + }; +} + +/*! + \brief parse the string descriptor + \param[in] psrc: source pointer containing the descriptor data + \param[in] pdest: destination address pointer + \param[in] len: length of the descriptor + \param[out] none + \retval operation status +*/ +static void usbh_strdesc_parse (uint8_t *psrc, uint8_t *pdest, uint16_t len) +{ + uint16_t str_len = 0U, index = 0U; + + /* the unicode string descriptor is not NULL-terminated. The string length is + * computed by substracting two from the value of the first byte of the descriptor. + */ + + /* check which is lower size, the size of string or the length of bytes read from the device */ + if (USB_DESCTYPE_STR == psrc[1]) { + /* make sure the descriptor is string type */ + + /* psrc[0] contains Size of Descriptor, subtract 2 to get the length of string */ + str_len = USB_MIN(psrc[0] - 2U, len); + + psrc += 2U; /* adjust the offset ignoring the string len and descriptor type */ + + for (index = 0U; index < str_len; index += 2U) { + /* copy only the string and ignore the unicode id, hence add the src */ + *pdest = psrc[index]; + + pdest++; + } + + *pdest = 0U; /* mark end of string */ + } +} + +/*! + \brief get the next descriptor header + \param[in] pbuf: pointer to buffer where the configuration descriptor set is available + \param[in] ptr: data popinter inside the configuration descriptor set + \param[out] none + \retval operation status +*/ +usb_desc_header *usbh_nextdesc_get (uint8_t *pbuf, uint16_t *ptr) +{ + usb_desc_header *pnext; + + *ptr += ((usb_desc_header *)pbuf)->bLength; + + pnext = (usb_desc_header *)((uint8_t *)pbuf + ((usb_desc_header *)pbuf)->bLength); + + return (pnext); +} + diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/usbh_pipe.c b/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/usbh_pipe.c new file mode 100644 index 0000000..5fb29f3 --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/usbh_pipe.c @@ -0,0 +1,174 @@ +/*! + \file usbh_pipe.c + \brief USB host mode pipe operation driver + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#include "../Include/usbh_pipe.h" + +static uint16_t usbh_freepipe_get (usb_core_driver *pudev); + +/*! + \brief create a pipe + \param[in] pudev: pointer to usb core instance + \param[in] pp_num: pipe number + \param[in] udev: USB device + \param[in] ep_type: endpoint type + \param[in] ep_mpl: endpoint max packet length + \param[out] none + \retval operation status +*/ +uint8_t usbh_pipe_create (usb_core_driver *pudev, + usb_dev_prop *udev, + uint8_t pp_num, + uint8_t ep_type, + uint16_t ep_mpl) +{ + usb_pipe *pp = &pudev->host.pipe[pp_num]; + + pp->dev_addr = udev->addr; + pp->dev_speed = udev->speed; + pp->ep.type = ep_type; + pp->ep.mps = ep_mpl; + pp->ping = udev->speed == PORT_SPEED_HIGH; + + usb_pipe_init (pudev, pp_num); + + return HC_OK; +} + +/*! + \brief modify a pipe + \param[in] pudev: pointer to usb core instance + \param[in] pp_num: pipe number + \param[in] dev_addr: device address + \param[in] dev_speed: device speed + \param[in] ep_type: endpoint type + \param[in] ep_mpl: endpoint max packet length + \param[out] none + \retval operation status +*/ +uint8_t usbh_pipe_update (usb_core_driver *pudev, + uint8_t pp_num, + uint8_t dev_addr, + uint32_t dev_speed, + uint16_t ep_mpl) +{ + usb_pipe *pp = &pudev->host.pipe[pp_num]; + + if ((pp->dev_addr != dev_addr) && (dev_addr)) { + pp->dev_addr = dev_addr; + } + + if ((pp->dev_speed != dev_speed) && (dev_speed)) { + pp->dev_speed = dev_speed; + } + + if ((pp->ep.mps != ep_mpl) && (ep_mpl)) { + pp->ep.mps = ep_mpl; + } + + usb_pipe_init (pudev, pp_num); + + return HC_OK; +} + +/*! + \brief allocate a new pipe + \param[in] pudev: pointer to usb core instance + \param[in] ep_addr: endpoint address + \param[out] none + \retval operation status +*/ +uint8_t usbh_pipe_allocate (usb_core_driver *pudev, uint8_t ep_addr) +{ + uint16_t pp_num = usbh_freepipe_get (pudev); + + if (HC_ERROR != pp_num) { + pudev->host.pipe[pp_num].in_used = 1U; + pudev->host.pipe[pp_num].ep.dir = EP_DIR(ep_addr); + pudev->host.pipe[pp_num].ep.num = EP_ID(ep_addr); + } + + return pp_num; +} + +/*! + \brief free a pipe + \param[in] pudev: pointer to usb core instance + \param[in] pp_num: pipe number + \param[out] none + \retval operation status +*/ +uint8_t usbh_pipe_free (usb_core_driver *pudev, uint8_t pp_num) +{ + if (pp_num < HC_MAX) { + pudev->host.pipe[pp_num].in_used = 0U; + } + + return USBH_OK; +} + +/*! + \brief delete all USB host pipe + \param[in] pudev: pointer to usb core instance + \param[out] none + \retval operation status +*/ +uint8_t usbh_pipe_delete (usb_core_driver *pudev) +{ + uint8_t pp_num = 0U; + + for (pp_num = 2U; pp_num < HC_MAX; pp_num++) { + pudev->host.pipe[pp_num] = (usb_pipe) {0}; + } + + return USBH_OK; +} + +/*! + \brief get a free pipe number for allocation + \param[in] pudev: pointer to usb core instance + \param[out] none + \retval operation status +*/ +static uint16_t usbh_freepipe_get (usb_core_driver *pudev) +{ + uint8_t pp_num = 0U; + + for (pp_num = 0U; pp_num < HC_MAX; pp_num++) { + if (pudev->host.pipe[pp_num].in_used == 0U) { + return pp_num; + } + } + + return HC_ERROR; +} diff --git a/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/usbh_transc.c b/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/usbh_transc.c new file mode 100644 index 0000000..433f18a --- /dev/null +++ b/RISC-V/Firmware/GD32VF103_usbfs_driver/Source/usbh_transc.c @@ -0,0 +1,391 @@ +/*! + \file usbh_transc.c + \brief USB host mode transactions driver + + \version 2019-06-05, V1.0.0, firmware for GD32 USBFS&USBHS +*/ + +/* + Copyright (c) 2019, GigaDevice Semiconductor Inc. + + Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. +*/ + +#include "../Include/drv_usb_hw.h" +#include "../Include/usbh_transc.h" + +/*! + \brief prepare a pipe and start a transfer + \param[in] pudev: pointer to usb core instance + \param[in] pp_num: pipe number + \param[out] none + \retval operation status +*/ +static uint32_t usbh_request_submit (usb_core_driver *pudev, uint8_t pp_num) +{ + pudev->host.pipe[pp_num].urb_state = URB_IDLE; + pudev->host.pipe[pp_num].xfer_count = 0U; + + return usb_pipe_xfer (pudev, pp_num); +} + +/*! + \brief send the setup packet to the USB device + \param[in] pudev: pointer to usb core instance + \param[in] buf: data buffer which will be sent to USB device + \param[in] pp_num: pipe number + \param[out] none + \retval operation status +*/ +usbh_status usbh_ctlsetup_send (usb_core_driver *pudev, uint8_t *buf, uint8_t pp_num) +{ + usb_pipe *pp = &pudev->host.pipe[pp_num]; + + pp->DPID = PIPE_DPID_SETUP; + pp->xfer_buf = buf; + pp->xfer_len = USB_SETUP_PACKET_LEN; + + return (usbh_status)usbh_request_submit (pudev, pp_num); +} + +/*! + \brief send a data packet to the USB device + \param[in] pudev: pointer to usb core instance + \param[in] buf: data buffer which will be sent to USB device + \param[in] pp_num: pipe number + \param[in] len: length of the data to be sent + \param[out] none + \retval operation status +*/ +usbh_status usbh_data_send (usb_core_driver *pudev, uint8_t *buf, uint8_t pp_num, uint16_t len) +{ + usb_pipe *pp = &pudev->host.pipe[pp_num]; + + pp->xfer_buf = buf; + pp->xfer_len = len; + + switch (pp->ep.type) { + case USB_EPTYPE_CTRL: + if (0U == len) { + pp->data_toggle_out = 1U; + } + + pp->DPID = PIPE_DPID[pp->data_toggle_out]; + break; + + case USB_EPTYPE_INTR: + pp->DPID = PIPE_DPID[pp->data_toggle_out]; + + pp->data_toggle_out ^= 1U; + break; + + case USB_EPTYPE_BULK: + pp->DPID = PIPE_DPID[pp->data_toggle_out]; + break; + + case USB_EPTYPE_ISOC: + pp->DPID = PIPE_DPID[0]; + break; + + default: + break; + } + + usbh_request_submit (pudev, pp_num); + + return USBH_OK; +} + +/*! + \brief receive a data packet from the USB device + \param[in] pudev: pointer to usb core instance + \param[in] buf: data buffer which will be received from USB device + \param[in] pp_num: pipe number + \param[in] len: length of the data to be received + \param[out] none + \retval operation status +*/ +usbh_status usbh_data_recev (usb_core_driver *pudev, uint8_t *buf, uint8_t pp_num, uint16_t len) +{ + usb_pipe *pp = &pudev->host.pipe[pp_num]; + + pp->xfer_buf = buf; + pp->xfer_len = len; + + switch (pp->ep.type) { + case USB_EPTYPE_CTRL: + pp->DPID = PIPE_DPID[1]; + break; + + case USB_EPTYPE_INTR: + pp->DPID = PIPE_DPID[pp->data_toggle_in]; + + /* Toggle DATA PID */ + pp->data_toggle_in ^= 1U; + break; + + case USB_EPTYPE_BULK: + pp->DPID = PIPE_DPID[pp->data_toggle_in]; + break; + + case USB_EPTYPE_ISOC: + pp->DPID = PIPE_DPID[0]; + break; + + default: + break; + } + + usbh_request_submit (pudev, pp_num); + + return USBH_OK; +} + +/*! + \brief wait for USB URB(USB request block) state + \param[in] pudev: pointer to USB core instance + \param[in] puhost: pointer to USB host + \param[in] pp_num: pipe number + \param[in] wait_time: wait time + \param[out] none + \retval USB URB state +*/ +static usb_urb_state usbh_urb_wait (usb_core_driver *pudev, usbh_host *puhost, uint8_t pp_num, uint32_t wait_time) +{ + usb_urb_state urb_status = URB_IDLE; + + while (URB_DONE != (urb_status = usbh_urbstate_get(pudev, pp_num))) { + if (URB_NOTREADY == urb_status) { + break; + } else if (URB_STALL == urb_status) { + puhost->control.ctl_state = CTL_SETUP; + break; + } else if (URB_ERROR == urb_status) { + puhost->control.ctl_state = CTL_ERROR; + break; + } else if ((wait_time > 0U) && \ + ((usb_curframe_get(pudev)- puhost->control.timer) > wait_time)) { + /* timeout for in transfer */ + puhost->control.ctl_state = CTL_ERROR; + break; + } else { + /* no operation, just wait */ + } + } + + return urb_status; +} + +/*! + \brief USB setup transaction + \param[in] pudev: pointer to USB core instance + \param[in] puhost: pointer to USB host + \param[out] none + \retval none +*/ +static void usbh_setup_transc (usb_core_driver *pudev, usbh_host *puhost) +{ + usb_urb_state urb_status = URB_IDLE; + + /* send a SETUP packet */ + usbh_ctlsetup_send (pudev, + puhost->control.setup.data, + puhost->control.pipe_out_num); + + urb_status = usbh_urb_wait (pudev, puhost, puhost->control.pipe_out_num, 0U); + + if (URB_DONE == urb_status) { + uint8_t dir = (puhost->control.setup.req.bmRequestType & USB_TRX_MASK); + + if (puhost->control.setup.req.wLength) { + if (USB_TRX_IN == dir) { + puhost->control.ctl_state = CTL_DATA_IN; + } else { + puhost->control.ctl_state = CTL_DATA_OUT; + } + } else { + if (USB_TRX_IN == dir) { + puhost->control.ctl_state = CTL_STATUS_OUT; + } else { + puhost->control.ctl_state = CTL_STATUS_IN; + } + } + + /* set the delay timer to enable timeout for data stage completion */ + puhost->control.timer = usb_curframe_get(pudev); + } +} + +/*! + \brief USB data IN transaction + \param[in] pudev: pointer to USB core instance + \param[in] puhost: pointer to USB host + \param[out] none + \retval none +*/ +static void usbh_data_in_transc (usb_core_driver *pudev, usbh_host *puhost) +{ + usb_urb_state urb_status = URB_IDLE; + + usbh_data_recev (pudev, + puhost->control.buf, + puhost->control.pipe_in_num, + puhost->control.ctl_len); + + urb_status = usbh_urb_wait (pudev, puhost, puhost->control.pipe_in_num, DATA_STAGE_TIMEOUT); + + if (URB_DONE == urb_status) { + puhost->control.ctl_state = CTL_STATUS_OUT; + + puhost->control.timer = usb_curframe_get(pudev); + } +} + +/*! + \brief USB data OUT transaction + \param[in] pudev: pointer to USB core instance + \param[in] puhost: pointer to USB host + \param[out] none + \retval none +*/ +static void usbh_data_out_transc (usb_core_driver *pudev, usbh_host *puhost) +{ + usb_urb_state urb_status = URB_IDLE; + + pudev->host.pipe[puhost->control.pipe_out_num].data_toggle_out = 1U; + + usbh_data_send (pudev, + puhost->control.buf, + puhost->control.pipe_out_num, + puhost->control.ctl_len); + + urb_status = usbh_urb_wait (pudev, puhost, puhost->control.pipe_out_num, DATA_STAGE_TIMEOUT); + + if (URB_DONE == urb_status) { + puhost->control.ctl_state = CTL_STATUS_IN; + + puhost->control.timer = usb_curframe_get(pudev); + } +} + +/*! + \brief USB status IN transaction + \param[in] pudev: pointer to USB core instance + \param[in] puhost: pointer to USB host + \param[out] none + \retval none +*/ +static void usbh_status_in_transc (usb_core_driver *pudev, usbh_host *puhost) +{ + uint8_t pp_num = puhost->control.pipe_in_num; + + usb_urb_state urb_status = URB_IDLE; + + usbh_data_recev (pudev, NULL, pp_num, 0U); + + urb_status = usbh_urb_wait (pudev, puhost, pp_num, NODATA_STAGE_TIMEOUT); + + if (URB_DONE == urb_status) { + puhost->control.ctl_state = CTL_FINISH; + } +} + +/*! + \brief USB status OUT transaction + \param[in] pudev: pointer to USB core instance + \param[in] puhost: pointer to USB host + \param[out] none + \retval none +*/ +static void usbh_status_out_transc (usb_core_driver *pudev, usbh_host *puhost) +{ + uint8_t pp_num = puhost->control.pipe_out_num; + + usb_urb_state urb_status = URB_IDLE; + + pudev->host.pipe[pp_num].data_toggle_out ^= 1U; + + usbh_data_send (pudev, NULL, pp_num, 0U); + + urb_status = usbh_urb_wait (pudev, puhost, pp_num, NODATA_STAGE_TIMEOUT); + + if (URB_DONE == urb_status) { + puhost->control.ctl_state = CTL_FINISH; + } +} + +/*! + \brief USB control transfer handler + \param[in] pudev: pointer to USB core instance + \param[in] puhost: pointer to USB host + \param[out] none + \retval operation status +*/ +usbh_status usbh_ctl_handler (usb_core_driver *pudev, usbh_host *puhost) +{ + usbh_status status = USBH_BUSY; + + switch (puhost->control.ctl_state) { + case CTL_SETUP: + usbh_setup_transc (pudev, puhost); + break; + + case CTL_DATA_IN: + usbh_data_in_transc (pudev, puhost); + break; + + case CTL_DATA_OUT: + usbh_data_out_transc (pudev, puhost); + break; + + case CTL_STATUS_IN: + usbh_status_in_transc (pudev, puhost); + break; + + case CTL_STATUS_OUT: + usbh_status_out_transc (pudev, puhost); + break; + + case CTL_FINISH: + puhost->control.ctl_state = CTL_IDLE; + + status = USBH_OK; + break; + + case CTL_ERROR: + if (++puhost->control.error_count <= USBH_MAX_ERROR_COUNT) { + /* do the transmission again, starting from SETUP packet */ + puhost->control.ctl_state = CTL_SETUP; + } else { + status = USBH_FAIL; + } + break; + + default: + break; + } + + return status; +} +