parent
2e8b5aa51c
commit
91a82403fe
@ -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 */
|
@ -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 */
|
||||
|
@ -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 */
|
@ -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 */
|
@ -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 */
|
@ -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 */
|
@ -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 */
|
@ -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 */
|
||||
|
@ -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 */
|
@ -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 */
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in new issue