/*
 * Copyright (c) 2022 OpenLuat & AirM2M
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "user.h"
#define USB_FIFO_MAX	(512)
#define USB_FIFO_DW_DAX	(128)

/**
  * 结构说明：调试控制寄存器(USBPHY_CR1)结构
  * 偏移地址：0x0108
  * 初 始 值：0x004921AE
  * 属    性：RW
  * 宽    度：32bit
  */
typedef union _USBPHY_CR1_TypeDef
{
    uint32_t d32;
    struct{
        uint32_t txpreemphasistune          : 1;    /* */
        uint32_t txrisetune                 : 2;    /* */
        uint32_t txvreftune                 : 4;    /* */
        uint32_t txfslstune                 : 4;    /* */
        uint32_t sqrxtune                   : 3;    /* */
        uint32_t compdistune                : 3;    /* */
        uint32_t otgtune                    : 3;    /* */
        uint32_t loopback_enb               : 1;    /* */
        uint32_t otg_disable                : 1;    /* */
        uint32_t commononn                  : 1;    /* */
        uint32_t vatestenb                  : 1;    /* */
        uint32_t lsbist                     : 1;    /* */
        uint32_t fsbist                     : 1;    /* */
        uint32_t hsbist                     : 1;    /* */
        uint32_t bisten                     : 1;    /* */
        uint32_t usb_iddq                   : 1;    /* */
        uint32_t stop_ck_for_suspend        : 1;    /* */
        uint32_t bist_done                  : 1;    /* */
        uint32_t bist_error                 : 1;    /* */
    } b;
} USBPHY_CR1_TypeDef;

/**
  * 结构说明：调试控制寄存器(USBPHY_CR3)结构
  * 偏移地址：0x010C
  * 初 始 值：0x00000000
  * 属    性：RW
  * 宽    度：32bit
  */
typedef union _USBPHY_CR3_TypeDef
{
    uint32_t d32;
    struct{
        uint32_t idpullup	                : 1;    /* 用于操作 USB PHY的idpullup，启动PHY探测ID状态 */
        uint32_t iddig                      : 1;    /* PHY 输出的ID状态信号，用于软件查询 */
        uint32_t reserved2_31               : 29;
    } b;
} USBPHY_CR3_TypeDef;

typedef struct
{
	// Common USB Registers. 0x00 - 0x0F.
	__IO uint8_t FADDR;          // Peripheral Mode Only.
	union
	{
	    __IO uint8_t POWER;
	    struct
	    {
	    	__IO uint8_t en_suspendM    : 1;
	    	__IO uint8_t suspend_mode   : 1;
	    	__IO uint8_t resume         : 1;
	    	__IO uint8_t reset          : 1;
	    	__IO uint8_t HS_mode        : 1;	//不支持
	    	__IO uint8_t HS_enab        : 1;	//不支持
	    	__IO uint8_t soft_conn      : 1;     /* Periphera mode only */
	    	__IO uint8_t ISO_update     : 1;     /* Periphera mode only */
	    } POWER_b;
	};
	union
	{
	    __IO uint16_t INTRTX;
	    struct
	    {
	    	__IO uint16_t EP0_intp        : 1;
	    	__IO uint16_t EP1_tx_intp     : 1;
	    	__IO uint16_t EP2_tx_intp     : 1;
	    	__IO uint16_t EP3_tx_intp     : 1;
	    	__IO uint16_t EP4_tx_intp     : 1;
	    	__IO uint16_t EP5_tx_intp     : 1;
	    	__IO uint16_t EP6_tx_intp     : 1;
	    	__IO uint16_t EP7_tx_intp     : 1;
	    	__IO uint16_t EP8_tx_intp     : 1;
	    	__IO uint16_t EP9_tx_intp     : 1;
	    	__IO uint16_t EP10_tx_intp    : 1;
	    	__IO uint16_t EP11_tx_intp    : 1;
	    	__IO uint16_t EP12_tx_intp    : 1;
	    	__IO uint16_t EP13_tx_intp    : 1;
	    	__IO uint16_t EP14_tx_intp    : 1;
	    	__IO uint16_t EP15_tx_intp    : 1;
	    } INTRTX_b;
	};
	union
	{
		__IO     uint16_t    INTRRX;
	    struct
	    {
	        uint16_t reserved0               : 1;
	        uint16_t EP1_rx_intp             : 1;
	        uint16_t EP2_rx_intp             : 1;
	        uint16_t EP3_rx_intp             : 1;
	        uint16_t EP4_rx_intp             : 1;
	        uint16_t EP5_rx_intp             : 1;
	        uint16_t EP6_rx_intp             : 1;
	        uint16_t EP7_rx_intp             : 1;
	        uint16_t EP8_rx_intp             : 1;
	        uint16_t EP9_rx_intp             : 1;
	        uint16_t EP10_rx_intp            : 1;
	        uint16_t EP11_rx_intp            : 1;
	        uint16_t EP12_rx_intp            : 1;
	        uint16_t EP13_rx_intp            : 1;
	        uint16_t EP14_rx_intp            : 1;
	        uint16_t EP15_rx_intp            : 1;
	    } INTRRX_b;
	};
	union
	{
	    __IO    uint16_t    INTRTXE;
	    struct
	    {
	        uint16_t en_EP0_intp        : 1;
	        uint16_t en_EP1_tx_intp     : 1;
	        uint16_t en_EP2_tx_intp     : 1;
	        uint16_t en_EP3_tx_intp     : 1;
	        uint16_t en_EP4_tx_intp     : 1;
	        uint16_t en_EP5_tx_intp     : 1;
	        uint16_t en_EP6_tx_intp     : 1;
	        uint16_t en_EP7_tx_intp     : 1;
	        uint16_t en_EP8_tx_intp     : 1;
	        uint16_t en_EP9_tx_intp     : 1;
	        uint16_t en_EP10_tx_intp    : 1;
	        uint16_t en_EP11_tx_intp    : 1;
	        uint16_t en_EP12_tx_intp    : 1;
	        uint16_t en_EP13_tx_intp    : 1;
	        uint16_t en_EP14_tx_intp    : 1;
	        uint16_t en_EP15_tx_intp    : 1;
	    } INTRTXE_b;
	};
	union
	{
	    __IO    uint16_t    INTRRXE;
	    struct
	    {
	        uint16_t reserved0                  : 1;
	        uint16_t en_EP1_rx_intp             : 1;
	        uint16_t en_EP2_rx_intp             : 1;
	        uint16_t en_EP3_rx_intp             : 1;
	        uint16_t en_EP4_rx_intp             : 1;
	        uint16_t en_EP5_rx_intp             : 1;
	        uint16_t en_EP6_rx_intp             : 1;
	        uint16_t en_EP7_rx_intp             : 1;
	        uint16_t en_EP8_rx_intp             : 1;
	        uint16_t en_EP9_rx_intp             : 1;
	        uint16_t en_EP10_rx_intp            : 1;
	        uint16_t en_EP11_rx_intp            : 1;
	        uint16_t en_EP12_rx_intp            : 1;
	        uint16_t en_EP13_rx_intp            : 1;
	        uint16_t en_EP14_rx_intp            : 1;
	        uint16_t en_EP15_rx_intp            : 1;
	    } INTRRXE_b;
	};
	union
	{
	    __IO     uint8_t     INTRUSB;
	    struct
	    {
	        uint8_t suspend         : 1;    /* Set when Suspend signaling is detected on the bus. Only valid in Peripheral mode. */
	        uint8_t resume          : 1;    /* Set when Resume signaling is detected on the bus while the MUSBMHDRC is in Suspend mode. */
	        uint8_t reset_babble    : 1;    /* Reset: Set in Peripheral mode when Reset signaling is detected on the bus.
	                                         * Babble: Set in Host mode when babble is detected. Note: Only active after first SOF has been sent.
	                                         */
	        uint8_t sof             : 1;    /* Set when a new frame starts.  */
	        uint8_t conn            : 1;    /* Set when a device connection is detected. Only valid in Host mode. Valid at all transaction speeds. */
	        uint8_t discon          : 1;    /* Set in Host mode when a device disconnect is detected. Set in Peripheral mode when a session ends. Valid at all transaction speeds. */
	        uint8_t sess_req        : 1;    /* Set when Session Request signaling has been detected. Only valid when MUSBMHDRC is A device. */
	        uint8_t VBus_error      : 1;    /* Set when VBus drops below the VBus Valid threshold during a session. Only valid when MUSBMHDRC is A device. */
	    } INTRUSB_b;
	};
	union
	{
	    __IO    uint8_t     INTRUSBE;
	    struct
	    {
	        uint8_t en_suspend         : 1;
	        uint8_t en_resume          : 1;
	        uint8_t en_reset_babble    : 1;
	        uint8_t en_sof             : 1;
	        uint8_t en_conn            : 1;
	        uint8_t en_discon          : 1;
	        uint8_t en_sess_req        : 1;
	        uint8_t en_VBus_error      : 1;
	    } INTRUSBE_b;
	};
	union
	{
	    __IO     uint16_t    FRAME;
	    struct
	    {
	        uint16_t frame_number       : 11;
	        uint16_t reserved11_15      : 5;    /* Always return 0 */
	    } FRAME_b;
	};
	__IO    uint8_t     INDEX;
    __IO    uint8_t     TESTMODE;
    // Indexed CSR. 0x10 - 0x1F.
    union
	{
        __IO    uint16_t    TXMAXP;
        struct
        {
        	__IO   uint16_t max_payload_tran           : 11;   /* Bits 10:0 define(in bytes)the maximum payload transmitted in single transaction.
                                                         * The value set can be up to 1024 bytes but is subject to the constraints place by
                                                         * the USB Specification on packet sizes for Bulk,Interrupt and Isochronous transfers
                                                         * in Full-speed and High-speed operations.
                                                         */
        	__IO   uint16_t ex_max                     : 5;
        } TXMAXP_b;
	};
    union
    {
        __IO    uint8_t     CSR0L;
        __IO    uint8_t     TXCSRL;
        struct
        {
        	__IO   uint8_t rx_pkt_rdy                  : 1;    /* This bit is set when a data packet has been received. An interrupt is
                                                         * generated when this bit is set. The CPU clear this bit by setting the
                                                         * ServicedRxPktRdy bit.
                                                         */
        	__IO   uint8_t tx_pkt_rdy                  : 1;    /* The CPU sets this bits after loading a data packet into the FIFO. It is clear
                                                         * automatically when a data packet has been transmitted. An interrupt is also
                                                         * generated at this point(if enabled).
                                                         */
        	__IO   uint8_t sent_stall                  : 1;    /* This bit is set when a STALL handshake is transmitted.
                                                         * The CPU should clear this bit.
                                                         */
        	__IO   uint8_t data_end                    : 1;    /* The CPU sets this bit:
                                                         * 1. When setting TxPktRdy for the last data packet.
                                                         * 2. When clearing RxPktRdy after unloading the last data packet.
                                                         * 3. When setting TxPktRdy for zero length data packet.
                                                         * It is cleared automatically.
                                                         */
        	__IO   uint8_t setup_end                   : 1;    /* This bit will be set when a control transaction ends before the DataEnd
                                                         * bit has been set. An interrupt will be generated and the FIFO flushed at
                                                         * this time.The bit is cleared by the CPU writing a 1 to the ServicedSetupEnd bit.
                                                         */
        	__IO   uint8_t send_stall                  : 1;    /* The CPU write a 1 to this bit to terminate the current transaction.
                                                         * The STALL handshake will be transmitted and then this bit will be
                                                         * cleared automatically.
                                                         */
        	__IO   uint8_t serviced_rxpktrdy           : 1;    /* The CPU write a 1 to this bit to clear the RxPktRdy bit.
                                                         * It is Cleared automatically.
                                                         */
        	__IO   uint8_t serviced_setupend           : 1;    /* The CPU write a 1 to this bit to clear the SetupEnd bit.
                                                         * It is Cleared automatically.
                                                         */
        } CSR0L_DEV_b;
        struct
        {
        	__IO   uint8_t rx_pkt_rdy                  : 1;    /* This bit is set when a data packet has been received.An interrupt is generated
                                                         * (If enabled)when this bit set.The CPU should clear this bit when the packet has
                                                         * been read from the FIFO.
                                                         */
        	__IO   uint8_t tx_pkt_rdy                  : 1;    /* The CPU sets this bit after loading a data packet into the FIFO.It is cleared
                                                         * automatically when a data packet has been transmitted. An interrupt is also
                                                         * generated at this point(If enabled).
                                                         */
        	__IO   uint8_t rx_stall                    : 1;    /* This bit is set when a STALL handshake is received. The CPU should clear this bit. */
        	__IO   uint8_t setup_pkt                   : 1;    /* The CPU sets this bit,at the TxPktRdy bit is set,to  send a SETUP token instead
                                                         * of an OUT token for the transaction. Note: Setting this bit also clear the Data
                                                         * Toggle.
                                                         */
        	__IO   uint8_t error                       : 1;    /* This bit will be set when three attempts have been made to perform a transaction
                                                         * with no response from the peripheral.The CPU should clear this bit.An interrupt
                                                         * is generated when this bit is set.
                                                         */
        	__IO   uint8_t req_pkt                     : 1;    /* The CPU sets this bit to request an IN transaction.
                                                         * It is cleared when RxPktRdy is set.
                                                         */
        	__IO   uint8_t status_pkt                  : 1;    /* The CPU sets this bit at the same time as the TxPktRdy or ReqPkt bit is set,
                                                         * to perform a status stage transaction. Setting this bit ensures that the data
                                                         * toggle is set to 1 so that a DATA1 packet is used for the Status Stage transaction.
                                                         */
        	__IO   uint8_t nak_timeout                 : 1;    /* This bit will be set when Endpoint 0 is halted following the receipt for longer
                                                         * than the time set by the NAKLimit0 register. The CPU should clear this bit to allow
                                                         * the endpoint to continue.
                                                         */
        } CSR0L_HOST_b;
        struct
        {
        	__IO   uint8_t tx_pkt_rdy                  : 1;    /* The CPU sets this bit after loading a data packet into the FIFO. */
        	__IO   uint8_t fifo_not_empty              : 1;    /* The USB sets this bit when there is at least 1 packet in the TX FIFO.  */
        	__IO   uint8_t under_run                   : 1;    /* The USB sets this bit if an IN token is received when TxPktRdy is not set. The CPU should clear this bit.  */
        	__IO   uint8_t flush_fifo                  : 1;    /* The CPU writes a 1 to this bit to flush the latest packet from the endpoint TX FIFO */
        	__IO   uint8_t send_stall                  : 1;    /* The CPU writes a 1 to this bit to issue a STALL handshake to an IN token.The CPU
                                                         * clears this bit to terminate the stall condition.
                                                         * Note:This bit has no effect where the endpoint is being used for Isochronous transfers.
                                                         */
        	__IO   uint8_t sent_stall                  : 1;    /* This bit is set when a STALL handshake is transmitted.The FIFO is flushed and
                                                         * the TxPktRdy bit is cleared(see below).The CPU should clear this bit.
                                                         */
        	__IO   uint8_t clr_data_tog                : 1;    /* The CPU writes a 1 to this bit to reset the endpoint data toggle to 0. */
        	__IO   uint8_t incomp_tx                   : 1;    /* When the endpoint is being used for high-bandwidth Isochronous,this bit is set to
                                                         * indicate where a large packet has been split into 2 or 3 packets for transmission
                                                         * but insufficient IN tokens have been received to send all the parts.
                                                         * Note:In anything other than isochronous transfers,this bit will always return 0.
                                                         */
        } TXCSRL_DEV_b;
        struct
        {
        	__IO   uint8_t tx_pkt_rdy                  : 1;    /* The CPU sets this bit after loading a data packet into the FIFO. */
        	__IO   uint8_t fifo_not_empty              : 1;    /* The USB sets this bit when there is at least 1 packet in the TX FIFO.  */
        	__IO   uint8_t error                       : 1;
        	__IO   uint8_t flush_fifo                  : 1;    /* The CPU writes a 1 to this bit to flush the latest packet from the endpoint TX FIFO */
        	__IO   uint8_t setup_Pkt                   : 1;
            __IO   uint8_t Rx_stall                    : 1;
            __IO   uint8_t clr_data_tog                : 1;    /* The CPU writes a 1 to this bit to reset the endpoint data toggle to 0. */
            __IO   uint8_t NAK_timeout_incompTx        : 1;
        } TXCSRL_HOST_b;

    };
    union
    {
        __IO    uint8_t     CSR0H;
        __IO    uint8_t     TXCSRH;
        struct
        {
        	__IO   uint8_t flush_fifo              : 1;    /* The CPU writes a 1 to this bit to flush the next packet to be transmitted/read from
                                                     * the Endpoint 0 FIFO. The FIFO pointer is reset and the TxPktRdy/RxPktRdy bit(below) is
                                                     * cleared. Note:FlushFIFO should only be used when TxPktRdy/RxPktRdy is set.At other
                                                     * times, it may cause data to be corrupted.
                                                     */
        	__IO   uint8_t reserved1_7             : 7;    /* Unused. Return 0 when resd. */
        } CSR0H_DEV_b;
        struct
        {
        	__IO   uint8_t flush_fifo              : 1;    /* The CPU writes a 1 to this bit to flush the next packet to be transmitted/read from
                                                     * the Endpoint 0 FIFO. The FIFO pointer is reset and the TxPktRdy/RxPktRdy bit(below) is
                                                     * cleared. Note:FlushFIFO should only be used when TxPktRdy/RxPktRdy is set.At other
                                                     * times, it may cause data to be corrupted.
                                                     */
        	__IO   uint8_t data_toggle             : 1;    /* When read,this bit indicates the current state of the Endpoint 0 data toggle. If D10
                                                     * is high,this bit may be written with the written with the required setting of the data
                                                     * toggle.If D10 is low,any value written to this bit is ignored.
                                                     */
        	__IO   uint8_t data_toggle_wr_en       : 1;    /* The CPU written a 1 to this bit to enable the current state of Endpoint 0 data toggle
                                                     * to be written(see Data Toggle bit,below).This bit is automatically cleared once the new
                                                     * value is written.
                                                     */
        	__IO   uint8_t dis_ping                : 1;    /* The CPU writes a 1 to this bit to instruct the core not to issue PING tokens in data
                                                     * and status phases of a high-speed Control transfer(for use with devices that do not
                                                     * respond to PING).
                                                     */
        	__IO   uint8_t reserved1_7             : 4;    /* Unused. Return 0 when resd. */
        } CSR0H_HOST_b;
        struct
        {
        	__IO   uint8_t reserved0_1                 : 2;
        	__IO   uint8_t dma_req_mode                : 1;
        	__IO   uint8_t frc_data_tog                : 1;
        	__IO   uint8_t dma_req_enab                : 1;
        	__IO   uint8_t mode                        : 1;
        	__IO   uint8_t iso                         : 1;
        	__IO   uint8_t auto_set                    : 1;
        } TXCSRH_DEV_b;
        struct
        {
        	__IO   uint8_t data_toggle                 : 1;
        	__IO   uint8_t data_toggle_wren            : 1;
        	__IO   uint8_t dma_req_mode                : 1;
        	__IO   uint8_t frc_data_tog                : 1;
        	__IO   uint8_t dma_req_enab                : 1;
        	__IO   uint8_t mode                        : 1;
        	__IO   uint8_t reserved6                   : 1;
        	__IO   uint8_t auto_set                    : 1;
        } TXCSRH_HOST_b;
    };
    union
	{
        __IO    uint16_t    RXMAXP;
        struct
        {
        	__IO   uint16_t max_payload_tran               : 11;
        	__IO   uint16_t ex_max                         : 5;
        } RXMAXP_b;
	};
    union
	{
        __IO    uint8_t    	RXCSRL;
        struct
        {
        	__IO   uint8_t rx_pkt_rdy                  : 1;    /* This bit is set when a data packet has been received */
        	__IO   uint8_t fifo_full                   : 1;    /* */
        	__IO   uint8_t over_run                    : 1;    /* */
        	__IO   uint8_t data_error                  : 1;    /* */
        	__IO   uint8_t flush_fifo                  : 1;
        	__IO   uint8_t send_stall                  : 1;    /* The CPU writes a 1 to this bit to issue a STALL handshake. */
        	__IO   uint8_t sent_stall                  : 1;    /* This bit is set when a STALL handshake is transmitted. The CPU should clear this bit.  */
        	__IO   uint8_t clr_data_tog                : 1;
        } RXCSRL_DEV_b;
        struct
        {
        	__IO   uint8_t rx_pkt_rdy                  : 1;    /* This bit is set when a data packet has been received */
        	__IO   uint8_t fifo_full                   : 1;    /* */
        	__IO   uint8_t error                       : 1;    /* */
        	__IO   uint8_t data_error                  : 1;    /* */
        	__IO   uint8_t flush_fifo                  : 1;
        	__IO   uint8_t ReqPkt                      : 1;
        	__IO   uint8_t RxStall                     : 1;
            __IO   uint8_t clr_data_tog                : 1;
        } RXCSRL_HOST_b;
	};
    union
	{
    	__IO    uint8_t    	RXCSRH;
        struct
        {
    		__IO   uint8_t incomp_rx               : 1;
    		__IO   uint8_t reserved1_2             : 2;
    		__IO   uint8_t dma_req_mode            : 1;
    		__IO   uint8_t dis_nyet_pid_error      : 1;
    		__IO   uint8_t dma_req_enab            : 1;
    		__IO   uint8_t iso                     : 1;
    		__IO   uint8_t auto_clear              : 1;
        } RXCSRH_DEV_b;
        struct
        {
        	__IO   uint8_t incomp_rx               : 1;
        	__IO   uint8_t data_toggle             : 1;
        	__IO   uint8_t data_toggle_wren        : 1;
        	__IO   uint8_t dma_req_mode            : 1;
        	__IO   uint8_t PID_error               : 1;
        	__IO   uint8_t dma_req_enab            : 1;
        	__IO   uint8_t auto_req                : 1;
        	__IO   uint8_t auto_clear              : 1;
        } RXCSRH_HOST_b;
	};

    union
    {
        __IO     uint8_t     COUNT0;
        __IO     uint16_t    RXCOUNT;
        struct
        {
        	__IO     uint8_t ep0_rx_count                    : 7;
        	__IO     uint8_t reserved7                       : 1;
        } COUNT0_b;
    };
    union
    {
        __IO    uint8_t     TYPE0;      // Host Mode Only.
        __IO    uint8_t     TXTYPE;     // Host Mode Only.
        struct
        {
        	__IO    uint8_t reserved0_5             : 6;    /* Reserved */
        	__IO    uint8_t speed                   : 2;    /* Operating speed of the target device :
                                                     *      00:Unused(Note: If selected,the target will be using the same connectionn speed as the core.)
                                                     *      01:High
                                                     *      10:Full
                                                     *      11:Low
                                                     */
        } TYPE0_b;
        struct
        {
        	__IO    uint8_t target_EP_number        : 4;    /* Operating speed of the target device when the core is configured with the
                                                     * multipoint option:
                                                     *      00: Unused                  01: High
                                                     *      10: Full                    11: Low
                                                     * When the core is not configured with the multipoint option these bits should
                                                     * not be accessed.
                                                     */
        	__IO    uint8_t protocol                : 2;    /* The CPU should set this to select the required protocol for TX endpoint:
                                                     *       00: Control       01: Isochronous
                                                     *       10: Bulk          11: Interrupt
                                                     */
        	__IO    uint8_t speed                   : 2;    /* Operating speed of the target device when the core is configured with
                                                     * the multipoint option:
                                                     *      00:Unused        01: High      10: Full      11:Low
                                                     * when the core is not configured with the multipoint option these bits
                                                     * should not be accessed.
                                                     */
        } TXTYPE_b;
    };
    union
    {
        __IO    uint8_t     NAKLIMIT0;  // Host Mode Only.
        __IO    uint8_t     TXINTERVAL; // Host Mode Only.
        struct
        {
        	__IO    uint8_t Endpoint0_NAK_Limit         : 5;    /* Endpoint 0 NAK limit (m) */
        	__IO    uint8_t reserved5_7                 : 3;    /* Reserve */
        } NAKLIMIT0_b;
        struct
        {
        	__IO    uint8_t Tx_polling_interval      :8;
        } TXINTERVAL_b;
    };
    union
	{
        __IO    uint8_t     RXTYPE;         // Host Mode Only.
        struct
        {
        	__IO    uint8_t target_EP_number        : 4;    /* Operating speed of the target device when the core is configured with the
                                                     * multipoint option:
                                                     *      00: Unused                  01: High
                                                     *      10: Full                    11: Low
                                                     * When the core is not configured with the multipoint option these bits should
                                                     * not be accessed.
                                                     */
        	__IO    uint8_t protocol                : 2;    /* The CPU should set this to select the required protocol for TX endpoint:
                                                     *       00: Control       01: Isochronous
                                                     *       10: Bulk          11: Interrupt
                                                     */
        	__IO    uint8_t speed                   : 2;    /* Operating speed of the target device when the core is configured with
                                                     * the multipoint option:
                                                     *      00:Unused        01: High      10: Full      11:Low
                                                     * when the core is not configured with the multipoint option these bits
                                                     * should not be accessed.
                                                     */
        } RXTYPE_b;
	};

    __IO    uint8_t     RXINTERVAL;     // Host Mode Only.
            uint8_t     UNUSED0;
    union
    {
        __IO     uint8_t     CONFIGDATA;
        __IO     uint8_t     FIFOSIZE;
        struct
        {
        	__IO     uint8_t utmi_data_width             : 1;    /* Indicates selected UTMI+ data width. Always 0 indicating 8 bits. */
        	__IO     uint8_t soft_cone                   : 1;    /* Always "1" . Indicates Soft Connect/Disconnect.  */
        	__IO     uint8_t dyn_fifo_sizing             : 1;    /* When set to "1" indicates Dynamic FIFO Sizing option selected.  */
        	__IO     uint8_t hb_txe                      : 1;    /* When set to "1" indicates High-bandwidth TX ISO Endpoint Support selected */
        	__IO     uint8_t hb_rxe                      : 1;    /* When set to "1" indicates High-bandwidth Rx ISO Endpoint Support selected.  */
        	__IO     uint8_t big_endian                  : 1;    /* Always "0". Indicates Little Endian ordering.  */
        	__IO     uint8_t mp_txe                      : 1;    /* When set to "1" automatic splitting of bulk packets is selected */
        	__IO     uint8_t mp_rxe                      : 1;    /* When set to "1" automatic amalgamation of bulk packets is selected  */
        } CONFIGDATA_b;
        struct
        {
        	__IO     uint8_t tx_fifo_size            : 4;
        	__IO     uint8_t rx_fifo_size            : 4;
        } b;
    };
    union
    {
        // FIFOS, EP0 - EP15 0x20 - 0x5F.
    	__IO	uint8_t		byte;
    	__IO	uint16_t	word;
    	__IO	uint32_t	dword;
    } FIFOX[16];

    // OTG, DynFIFO + Version. 0x60 - 0x6F.
    union
	{
        __IO    uint8_t     DEVCTL;
        struct
        {
        	__IO    uint8_t session             : 1;        /* When operation as an 'A' device,this bit is set or cleared by the CPU to
                                                     * start or end a session. When operating as a 'B' device,this bit is set/cleared
                                                     * by the MUSBMHDRC when a session starts/ends. It is also set by the CPU to initiate
                                                     * the Session Request Protocol.When the MUSBMHDRC is in Suspend mode,the bit may be
                                                     * cleared by the CPU to perform a software disconnect.Note:Clearing this bit when the
                                                     * core is not suspended will result in undefined behavior.
                                                     */
        	__IO    uint8_t host_req            : 1;        /* When set,the MUSBMHDRC will initiate the Host Negotiation when Suspend
                                                     * mode is entered.It is cleared when Host Negotiation is completed.
                                                     */
        	__IO    uint8_t host_mode           : 1;        /* This Read-only bit is set when the MUSBMHDRC is acting as a Host. */
        	__IO    uint8_t VBus                : 2;        /* These Read-only bits encode the current VBus level as follows:
                                                     *            D4      D3       Meaning
                                                     *             0       0       Below SessionEnd
                                                     *             0       1       Above SessionEnd,below AValid
                                                     *             1       0       Above AValid,below VBus Valid
                                                     *             1       1       Above VBus Valid
                                                     */
        	__IO    uint8_t LSDev               : 1;        /* This Read-only bit is set when a low-speed device has been detected being
                                                     * connected to the port. Only valid in Host mode.
                                                     */
        	__IO    uint8_t FSDev               : 1;        /* This Read-only bit is set when a full-speed or high-speed device has been
                                                     * detected being connected to the port.(High-speed device are distinguished
                                                     * from full-speed by checking for high-speed chirps when the device is reset.)
                                                     * Only valid in Host mode.
                                                     */
        	__IO    uint8_t B_Device            : 1;        /* This Read-only bit indicates whether the MUSBMHDRC is operating
                                                     * as the 'A' device or the 'B' device.
                                                     *      0 => 'A' device;         1 => 'B' device.
                                                     * Only valid while a session is in progress. To determine the role
                                                     * when no session is in progress, set the session bit and read this bit.
                                                     * NOTE: If the core is in Force_Host mode(i.e. a session has been started
                                                     * with Testmode.D7 = 1),this bit will indicate the state of the HOSTDISCON
                                                     * input signal from the PHY.
                                                     */
        } DEVCTL_b;
	};
    union
	{
        __IO    uint8_t     MISC;
        struct
        {
        	__IO    uint8_t rx_edma             : 1;        /* 1'b0:DMA_REQ signal for all OUT Endpoints will be de-asserted when MAXP
                                                     *      bytes have been read to an endpoint.This is late mode.
                                                     * 1'b1:DMA_REQ signal for all OUT Endpoints will be de-asserted when MAXP-8
                                                     *      bytes have been read to an endpoint.This is early mode.
                                                     */
        	__IO    uint8_t tx_edma             : 1;        /* 1'b0:DMA_REQ signal for all IN Endpoints will be de-asserted when MAXP
                                                     *      bytes have been written to an endpoint.This is late mode.
                                                     * 1'b1:DMA_REQ signal for all IN Endpoints will be de-asserted when MAXP-8
                                                     *      bytes have been written to an endpoint.This is early mode.
                                                     */
        	__IO    uint8_t reserved2_7         : 6;        /* These bits are reserved. */
        } MISC_b;
	};
    union
	{
        __IO    uint8_t     TXFIFOSZ;
        struct
        {
        	__IO    uint8_t size                        : 4;
        	__IO    uint8_t double_packet_buffer        : 1;
        	__IO    uint8_t reserved5_7                 : 3;
        } TXFIFOSZ_b;
	};
    union
	{
        __IO    uint8_t     RXFIFOSZ;
        struct
        {
        	__IO    uint8_t size                        : 4;
        	__IO    uint8_t double_packet_buffer        : 1;
        	__IO    uint8_t reserved5_7                 : 3;
        } RXFIFOSZ_b;
	};
    __IO    uint16_t    TXFIFOADD;
    __IO    uint16_t    RXFIFOADD;

    union
    {
        __O     uint32_t    VCONTROL;
        __IO     uint32_t    VSTATUS;
    }VCONTROL_VSTATUS;
    union
	{
        __IO     uint16_t    HWVERS;
        struct
        {
        	__IO     uint16_t minor_version_number           : 10;
        	__IO     uint16_t major_version_number           : 5;
        	__IO     uint16_t rc                             : 1;
        } HWVERS_b;
	};

            uint8_t     UNUSED1[2];
	// ULPI & Addnl. Config. registers. 0x70 - 0x7F.
	__IO    uint8_t     ULPIVBUSCONTROL;
	__IO    uint8_t     ULPICARKITCONTROL;
	__IO    uint8_t     ULPIINTMASK;
	__IO     uint8_t     ULPIINTSRC;
	__IO    uint8_t     ULPIREGDATA;
	__IO    uint8_t     ULPIREGADDR;
	__IO    uint8_t     ULPIREGCONTROL;
	__IO     uint8_t     ULPIRAWDATA;
	union
	{
		__IO     uint8_t     EPINFO;
	    struct
	    {
			__IO     uint8_t tx_endpoint         : 4;
			__IO     uint8_t rx_endpoint         : 4;
	    } EPINFO_b;
	};
	union
	{
		__IO     uint8_t     RAMINFO;
	    struct
	    {
			__IO     uint8_t ram_bits            : 4;
			__IO     uint8_t dma_chans           : 4;
	    } RAMINFO_b;
	};
	union
	{
		__IO    uint8_t     LINKINFO;
	    struct
	    {
			__IO    uint8_t wtid                : 4;
			__IO    uint8_t wtcon               : 4;
	    } LINKINFO_b;
	};

	__IO    uint8_t     VPLEN;
	__IO    uint8_t     HS_EOF1;
	__IO    uint8_t     FS_EOF1;
	__IO    uint8_t     LS_EOF1;
	union
	{
		__IO    uint8_t     SOFT_RST;
	    struct
	    {
			__IO    uint8_t nrst                : 1;
			__IO    uint8_t nrstx               : 1;
			__IO    uint8_t reserved2_7         : 6;
	    } SOFT_RST_b;
	};

	struct
	{
	    // TADDR Epn (n = 0 - 15). 0x80 - 0xFF.
	    __IO    uint8_t     TXFUNCADDR;
	            uint8_t     UNUSED0;
	    __IO    uint8_t     TXHUBADDR;
	    __IO    uint8_t     TXHUBPORT;
	    __IO    uint8_t     RXFUNCADDR;
	            uint8_t     UNUSED1;
	    __IO    uint8_t     RXHUBADDR;
	    __IO    uint8_t     RXHUBPORT;
	} AMCS[16];
	struct
	{
	    // CSR EPn (n = 0 - 15). 0x100 - 0x1FF;
	    union
		{
	        __IO    uint16_t    TXMAXP;
	        struct
	        {
	        	__IO   uint16_t max_payload_tran           : 11;   /* Bits 10:0 define(in bytes)the maximum payload transmitted in single transaction.
	                                                         * The value set can be up to 1024 bytes but is subject to the constraints place by
	                                                         * the USB Specification on packet sizes for Bulk,Interrupt and Isochronous transfers
	                                                         * in Full-speed and High-speed operations.
	                                                         */
	        	__IO   uint16_t ex_max                     : 5;
	        } TXMAXP_b;
		};
	    union
	    {
	        __IO    uint8_t     CSR0L;
	        __IO    uint8_t     TXCSRL;
	        struct
	        {
	        	__IO   uint8_t rx_pkt_rdy                  : 1;    /* This bit is set when a data packet has been received. An interrupt is
	                                                         * generated when this bit is set. The CPU clear this bit by setting the
	                                                         * ServicedRxPktRdy bit.
	                                                         */
	        	__IO   uint8_t tx_pkt_rdy                  : 1;    /* The CPU sets this bits after loading a data packet into the FIFO. It is clear
	                                                         * automatically when a data packet has been transmitted. An interrupt is also
	                                                         * generated at this point(if enabled).
	                                                         */
	        	__IO   uint8_t sent_stall                  : 1;    /* This bit is set when a STALL handshake is transmitted.
	                                                         * The CPU should clear this bit.
	                                                         */
	        	__IO   uint8_t data_end                    : 1;    /* The CPU sets this bit:
	                                                         * 1. When setting TxPktRdy for the last data packet.
	                                                         * 2. When clearing RxPktRdy after unloading the last data packet.
	                                                         * 3. When setting TxPktRdy for zero length data packet.
	                                                         * It is cleared automatically.
	                                                         */
	        	__IO   uint8_t setup_end                   : 1;    /* This bit will be set when a control transaction ends before the DataEnd
	                                                         * bit has been set. An interrupt will be generated and the FIFO flushed at
	                                                         * this time.The bit is cleared by the CPU writing a 1 to the ServicedSetupEnd bit.
	                                                         */
	        	__IO   uint8_t send_stall                  : 1;    /* The CPU write a 1 to this bit to terminate the current transaction.
	                                                         * The STALL handshake will be transmitted and then this bit will be
	                                                         * cleared automatically.
	                                                         */
	        	__IO   uint8_t serviced_rxpktrdy           : 1;    /* The CPU write a 1 to this bit to clear the RxPktRdy bit.
	                                                         * It is Cleared automatically.
	                                                         */
	        	__IO   uint8_t serviced_setupend           : 1;    /* The CPU write a 1 to this bit to clear the SetupEnd bit.
	                                                         * It is Cleared automatically.
	                                                         */
	        } CSR0L_DEV_b;
	        struct
	        {
	        	__IO   uint8_t rx_pkt_rdy                  : 1;    /* This bit is set when a data packet has been received.An interrupt is generated
	                                                         * (If enabled)when this bit set.The CPU should clear this bit when the packet has
	                                                         * been read from the FIFO.
	                                                         */
	        	__IO   uint8_t tx_pkt_rdy                  : 1;    /* The CPU sets this bit after loading a data packet into the FIFO.It is cleared
	                                                         * automatically when a data packet has been transmitted. An interrupt is also
	                                                         * generated at this point(If enabled).
	                                                         */
	        	__IO   uint8_t rx_stall                    : 1;    /* This bit is set when a STALL handshake is received. The CPU should clear this bit. */
	        	__IO   uint8_t setup_pkt                   : 1;    /* The CPU sets this bit,at the TxPktRdy bit is set,to  send a SETUP token instead
	                                                         * of an OUT token for the transaction. Note: Setting this bit also clear the Data
	                                                         * Toggle.
	                                                         */
	        	__IO   uint8_t error                       : 1;    /* This bit will be set when three attempts have been made to perform a transaction
	                                                         * with no response from the peripheral.The CPU should clear this bit.An interrupt
	                                                         * is generated when this bit is set.
	                                                         */
	        	__IO   uint8_t req_pkt                     : 1;    /* The CPU sets this bit to request an IN transaction.
	                                                         * It is cleared when RxPktRdy is set.
	                                                         */
	        	__IO   uint8_t status_pkt                  : 1;    /* The CPU sets this bit at the same time as the TxPktRdy or ReqPkt bit is set,
	                                                         * to perform a status stage transaction. Setting this bit ensures that the data
	                                                         * toggle is set to 1 so that a DATA1 packet is used for the Status Stage transaction.
	                                                         */
	        	__IO   uint8_t nak_timeout                 : 1;    /* This bit will be set when Endpoint 0 is halted following the receipt for longer
	                                                         * than the time set by the NAKLimit0 register. The CPU should clear this bit to allow
	                                                         * the endpoint to continue.
	                                                         */
	        } CSR0L_HOST_b;
	        struct
	        {
	        	__IO   uint8_t tx_pkt_rdy                  : 1;    /* The CPU sets this bit after loading a data packet into the FIFO. */
	        	__IO   uint8_t fifo_not_empty              : 1;    /* The USB sets this bit when there is at least 1 packet in the TX FIFO.  */
	        	__IO   uint8_t under_run                   : 1;    /* The USB sets this bit if an IN token is received when TxPktRdy is not set. The CPU should clear this bit.  */
	        	__IO   uint8_t flush_fifo                  : 1;    /* The CPU writes a 1 to this bit to flush the latest packet from the endpoint TX FIFO */
	        	__IO   uint8_t send_stall                  : 1;    /* The CPU writes a 1 to this bit to issue a STALL handshake to an IN token.The CPU
	                                                         * clears this bit to terminate the stall condition.
	                                                         * Note:This bit has no effect where the endpoint is being used for Isochronous transfers.
	                                                         */
	        	__IO   uint8_t sent_stall                  : 1;    /* This bit is set when a STALL handshake is transmitted.The FIFO is flushed and
	                                                         * the TxPktRdy bit is cleared(see below).The CPU should clear this bit.
	                                                         */
	        	__IO   uint8_t clr_data_tog                : 1;    /* The CPU writes a 1 to this bit to reset the endpoint data toggle to 0. */
	        	__IO   uint8_t incomp_tx                   : 1;    /* When the endpoint is being used for high-bandwidth Isochronous,this bit is set to
	                                                         * indicate where a large packet has been split into 2 or 3 packets for transmission
	                                                         * but insufficient IN tokens have been received to send all the parts.
	                                                         * Note:In anything other than isochronous transfers,this bit will always return 0.
	                                                         */
	        } TXCSRL_DEV_b;
	        struct
	        {
	        	__IO   uint8_t tx_pkt_rdy                  : 1;    /* The CPU sets this bit after loading a data packet into the FIFO. */
	        	__IO   uint8_t fifo_not_empty              : 1;    /* The USB sets this bit when there is at least 1 packet in the TX FIFO.  */
	        	__IO   uint8_t error                       : 1;
	        	__IO   uint8_t flush_fifo                  : 1;    /* The CPU writes a 1 to this bit to flush the latest packet from the endpoint TX FIFO */
	        	__IO   uint8_t setup_Pkt                   : 1;
	            __IO   uint8_t Rx_stall                    : 1;
	            __IO   uint8_t clr_data_tog                : 1;    /* The CPU writes a 1 to this bit to reset the endpoint data toggle to 0. */
	            __IO   uint8_t NAK_timeout_incompTx        : 1;
	        } TXCSRL_HOST_b;

	    };
	    union
	    {
	        __IO    uint8_t     CSR0H;
	        __IO    uint8_t     TXCSRH;
	        struct
	        {
	        	__IO   uint8_t flush_fifo              : 1;    /* The CPU writes a 1 to this bit to flush the next packet to be transmitted/read from
	                                                     * the Endpoint 0 FIFO. The FIFO pointer is reset and the TxPktRdy/RxPktRdy bit(below) is
	                                                     * cleared. Note:FlushFIFO should only be used when TxPktRdy/RxPktRdy is set.At other
	                                                     * times, it may cause data to be corrupted.
	                                                     */
	        	__IO   uint8_t reserved1_7             : 7;    /* Unused. Return 0 when resd. */
	        } CSR0H_DEV_b;
	        struct
	        {
	        	__IO   uint8_t flush_fifo              : 1;    /* The CPU writes a 1 to this bit to flush the next packet to be transmitted/read from
	                                                     * the Endpoint 0 FIFO. The FIFO pointer is reset and the TxPktRdy/RxPktRdy bit(below) is
	                                                     * cleared. Note:FlushFIFO should only be used when TxPktRdy/RxPktRdy is set.At other
	                                                     * times, it may cause data to be corrupted.
	                                                     */
	        	__IO   uint8_t data_toggle             : 1;    /* When read,this bit indicates the current state of the Endpoint 0 data toggle. If D10
	                                                     * is high,this bit may be written with the written with the required setting of the data
	                                                     * toggle.If D10 is low,any value written to this bit is ignored.
	                                                     */
	        	__IO   uint8_t data_toggle_wr_en       : 1;    /* The CPU written a 1 to this bit to enable the current state of Endpoint 0 data toggle
	                                                     * to be written(see Data Toggle bit,below).This bit is automatically cleared once the new
	                                                     * value is written.
	                                                     */
	        	__IO   uint8_t dis_ping                : 1;    /* The CPU writes a 1 to this bit to instruct the core not to issue PING tokens in data
	                                                     * and status phases of a high-speed Control transfer(for use with devices that do not
	                                                     * respond to PING).
	                                                     */
	        	__IO   uint8_t reserved1_7             : 4;    /* Unused. Return 0 when resd. */
	        } CSR0H_HOST_b;
	        struct
	        {
	        	__IO   uint8_t reserved0_1                 : 2;
	        	__IO   uint8_t dma_req_mode                : 1;
	        	__IO   uint8_t frc_data_tog                : 1;
	        	__IO   uint8_t dma_req_enab                : 1;
	        	__IO   uint8_t mode                        : 1;
	        	__IO   uint8_t iso                         : 1;
	        	__IO   uint8_t auto_set                    : 1;
	        } TXCSRH_DEV_b;
	        struct
	        {
	        	__IO   uint8_t data_toggle                 : 1;
	        	__IO   uint8_t data_toggle_wren            : 1;
	        	__IO   uint8_t dma_req_mode                : 1;
	        	__IO   uint8_t frc_data_tog                : 1;
	        	__IO   uint8_t dma_req_enab                : 1;
	        	__IO   uint8_t mode                        : 1;
	        	__IO   uint8_t reserved6                   : 1;
	        	__IO   uint8_t auto_set                    : 1;
	        } TXCSRH_HOST_b;
	    };
	    union
		{
	        __IO    uint16_t    RXMAXP;
	        struct
	        {
	        	__IO   uint16_t max_payload_tran               : 11;
	        	__IO   uint16_t ex_max                         : 5;
	        } RXMAXP_b;
		};
	    union
		{
	        __IO    uint8_t    	RXCSRL;
	        struct
	        {
	        	__IO   uint8_t rx_pkt_rdy                  : 1;    /* This bit is set when a data packet has been received */
	        	__IO   uint8_t fifo_full                   : 1;    /* */
	        	__IO   uint8_t over_run                    : 1;    /* */
	        	__IO   uint8_t data_error                  : 1;    /* */
	        	__IO   uint8_t flush_fifo                  : 1;
	        	__IO   uint8_t send_stall                  : 1;    /* The CPU writes a 1 to this bit to issue a STALL handshake. */
	        	__IO   uint8_t sent_stall                  : 1;    /* This bit is set when a STALL handshake is transmitted. The CPU should clear this bit.  */
	        	__IO   uint8_t clr_data_tog                : 1;
	        } RXCSRL_DEV_b;
	        struct
	        {
	        	__IO   uint8_t rx_pkt_rdy                  : 1;    /* This bit is set when a data packet has been received */
	        	__IO   uint8_t fifo_full                   : 1;    /* */
	        	__IO   uint8_t error                       : 1;    /* */
	        	__IO   uint8_t data_error                  : 1;    /* */
	        	__IO   uint8_t flush_fifo                  : 1;
	        	__IO   uint8_t ReqPkt                      : 1;
	        	__IO   uint8_t RxStall                     : 1;
	            __IO   uint8_t clr_data_tog                : 1;
	        } RXCSRL_HOST_b;
		};
	    union
		{
	    	__IO    uint8_t    	RXCSRH;
	        struct
	        {
	    		__IO   uint8_t incomp_rx               : 1;
	    		__IO   uint8_t reserved1_2             : 2;
	    		__IO   uint8_t dma_req_mode            : 1;
	    		__IO   uint8_t dis_nyet_pid_error      : 1;
	    		__IO   uint8_t dma_req_enab            : 1;
	    		__IO   uint8_t iso                     : 1;
	    		__IO   uint8_t auto_clear              : 1;
	        } RXCSRH_DEV_b;
	        struct
	        {
	        	__IO   uint8_t incomp_rx               : 1;
	        	__IO   uint8_t data_toggle             : 1;
	        	__IO   uint8_t data_toggle_wren        : 1;
	        	__IO   uint8_t dma_req_mode            : 1;
	        	__IO   uint8_t PID_error               : 1;
	        	__IO   uint8_t dma_req_enab            : 1;
	        	__IO   uint8_t auto_req                : 1;
	        	__IO   uint8_t auto_clear              : 1;
	        } RXCSRH_HOST_b;
		};

	    union
	    {
	        __IO     uint16_t    RXCOUNT;
	        struct
	        {
	        	__IO     uint16_t ep_rx_count            : 14;
	        	__IO     uint16_t reserved14_15          : 2;
	        } RXCOUNT_b;
	    };
	    union
	    {
	        __IO    uint8_t     TYPE0;      // Host Mode Only.
	        __IO    uint8_t     TXTYPE;     // Host Mode Only.
	        struct
	        {
	        	__IO    uint8_t reserved0_5             : 6;    /* Reserved */
	        	__IO    uint8_t speed                   : 2;    /* Operating speed of the target device :
	                                                     *      00:Unused(Note: If selected,the target will be using the same connectionn speed as the core.)
	                                                     *      01:High
	                                                     *      10:Full
	                                                     *      11:Low
	                                                     */
	        } TYPE0_b;
	        struct
	        {
	        	__IO    uint8_t target_EP_number        : 4;    /* Operating speed of the target device when the core is configured with the
	                                                     * multipoint option:
	                                                     *      00: Unused                  01: High
	                                                     *      10: Full                    11: Low
	                                                     * When the core is not configured with the multipoint option these bits should
	                                                     * not be accessed.
	                                                     */
	        	__IO    uint8_t protocol                : 2;    /* The CPU should set this to select the required protocol for TX endpoint:
	                                                     *       00: Control       01: Isochronous
	                                                     *       10: Bulk          11: Interrupt
	                                                     */
	        	__IO    uint8_t speed                   : 2;    /* Operating speed of the target device when the core is configured with
	                                                     * the multipoint option:
	                                                     *      00:Unused        01: High      10: Full      11:Low
	                                                     * when the core is not configured with the multipoint option these bits
	                                                     * should not be accessed.
	                                                     */
	        } TXTYPE_b;
	    };
	    union
	    {
	        __IO    uint8_t     NAKLIMIT0;  // Host Mode Only.
	        __IO    uint8_t     TXINTERVAL; // Host Mode Only.
	        struct
	        {
	        	__IO    uint8_t Endpoint0_NAK_Limit         : 5;    /* Endpoint 0 NAK limit (m) */
	        	__IO    uint8_t reserved5_7                 : 3;    /* Reserve */
	        } NAKLIMIT0_b;
	        struct
	        {
	        	__IO    uint8_t Tx_polling_interval      :8;
	        } TXINTERVAL_b;
	    };
	    union
		{
	        __IO    uint8_t     RXTYPE;         // Host Mode Only.
	        struct
	        {
	        	__IO    uint8_t target_EP_number        : 4;    /* Operating speed of the target device when the core is configured with the
	                                                     * multipoint option:
	                                                     *      00: Unused                  01: High
	                                                     *      10: Full                    11: Low
	                                                     * When the core is not configured with the multipoint option these bits should
	                                                     * not be accessed.
	                                                     */
	        	__IO    uint8_t protocol                : 2;    /* The CPU should set this to select the required protocol for TX endpoint:
	                                                     *       00: Control       01: Isochronous
	                                                     *       10: Bulk          11: Interrupt
	                                                     */
	        	__IO    uint8_t speed                   : 2;    /* Operating speed of the target device when the core is configured with
	                                                     * the multipoint option:
	                                                     *      00:Unused        01: High      10: Full      11:Low
	                                                     * when the core is not configured with the multipoint option these bits
	                                                     * should not be accessed.
	                                                     */
	        } RXTYPE_b;
		};
	    union
		{
	        __IO    uint8_t     RXINTERVAL;     // Host Mode Only.
	        struct
	        {
	        	__IO    uint8_t Tx_polling_interval      :8;
	        } RXINTERVAL_b;
		};

	            uint8_t     UNUSED0;
	    union
	    {
	        __IO     uint8_t     CONFIGDATA;
	        __IO     uint8_t     FIFOSIZE;
	        struct
	        {
	        	__IO     uint8_t utmi_data_width             : 1;    /* Indicates selected UTMI+ data width. Always 0 indicating 8 bits. */
	        	__IO     uint8_t soft_cone                   : 1;    /* Always "1" . Indicates Soft Connect/Disconnect.  */
	        	__IO     uint8_t dyn_fifo_sizing             : 1;    /* When set to "1" indicates Dynamic FIFO Sizing option selected.  */
	        	__IO     uint8_t hb_txe                      : 1;    /* When set to "1" indicates High-bandwidth TX ISO Endpoint Support selected */
	        	__IO     uint8_t hb_rxe                      : 1;    /* When set to "1" indicates High-bandwidth Rx ISO Endpoint Support selected.  */
	        	__IO     uint8_t big_endian                  : 1;    /* Always "0". Indicates Little Endian ordering.  */
	        	__IO     uint8_t mp_txe                      : 1;    /* When set to "1" automatic splitting of bulk packets is selected */
	        	__IO     uint8_t mp_rxe                      : 1;    /* When set to "1" automatic amalgamation of bulk packets is selected  */
	        } CONFIGDATA_b;
	        struct
	        {
	        	__IO     uint8_t tx_fifo_size            : 4;
	        	__IO     uint8_t rx_fifo_size            : 4;
	        } b;
	    };
	} CSR[16];
	// Optional DMA Registers. 0x200 - 0x2FF.
    __IO    uint32_t    DMA_INTR;       /* Only one DMA INTR register */
    __IO    uint32_t    DMA_CNTL;
    __IO    uint32_t    DMA_ADDR;
    __IO    uint32_t    DMA_COUNT;
    		uint32_t	UNUSED2[60];
    // Extended Registers. 0x300 - 0x35F.
	__IO    uint16_t    RQPKTCOUNT[16]; // Host Mode Only.
			uint16_t    UNUSEDRQPK[16];
	union
	{
		__IO    uint16_t    RXDPKTBUFDIS;   // Rx DPktBufDis.
	    struct
	    {
			__IO    uint16_t reserved0                  : 1;
			__IO    uint16_t ep1_rx_dis                 : 1;
			__IO    uint16_t ep2_rx_dis                 : 1;
			__IO    uint16_t ep3_rx_dis                 : 1;
			__IO    uint16_t ep4_rx_dis                 : 1;
			__IO    uint16_t ep5_rx_dis                 : 1;
			__IO    uint16_t ep6_rx_dis                 : 1;
			__IO    uint16_t ep7_rx_dis                 : 1;
			__IO    uint16_t ep8_rx_dis                 : 1;
			__IO    uint16_t ep9_rx_dis                 : 1;
			__IO    uint16_t ep10_rx_dis                : 1;
			__IO    uint16_t ep11_rx_dis                : 1;
			__IO    uint16_t ep12_rx_dis                : 1;
			__IO    uint16_t ep13_rx_dis                : 1;
			__IO    uint16_t ep14_rx_dis                : 1;
			__IO    uint16_t ep15_rx_dis                : 1;
	    } RXDPKTBUFDIS_b;
	};
	union
	{
		__IO    uint16_t    TXDPKTBUFDIS;   // Tx DPktBufDis.
	    struct
	    {
			__IO    uint16_t reserved0                  : 1;
			__IO    uint16_t ep1_tx_dis                 : 1;
			__IO    uint16_t ep2_tx_dis                 : 1;
			__IO    uint16_t ep3_tx_dis                 : 1;
			__IO    uint16_t ep4_tx_dis                 : 1;
			__IO    uint16_t ep5_tx_dis                 : 1;
			__IO    uint16_t ep6_tx_dis                 : 1;
			__IO    uint16_t ep7_tx_dis                 : 1;
			__IO    uint16_t ep8_tx_dis                 : 1;
			__IO    uint16_t ep9_tx_dis                 : 1;
			__IO    uint16_t ep10_tx_dis                : 1;
			__IO    uint16_t ep11_tx_dis                : 1;
			__IO    uint16_t ep12_tx_dis                : 1;
			__IO    uint16_t ep13_tx_dis                : 1;
			__IO    uint16_t ep14_tx_dis                : 1;
			__IO    uint16_t ep15_tx_dis                : 1;
	    } TXDPKTBUFDIS_b;
	};

	__IO    uint16_t    C_T_UCH;
	__IO    uint16_t    C_T_HSRTN;
	__IO    uint16_t    C_T_HSBT;
			uint16_t	UNUSED3[11];
    // LPM Registers. 0x360 - 0x365.
	union
	{
		__IO     uint16_t    LPM_ATTR;
		struct
		{
			__IO     uint16_t link_state          : 4;   /* This value is provoided by the host to the peripheral to indicate what state the peripheral
												 * must transition to after the receipt and acceptance of a LPM transaction.
												 * LinkState = 4'h0 - Reserved
												 * LinkState = 4'h1 - Slep State(L1)
												 * LinkState = 4'h2 - Reserved
												 * LinkState = 4'h3 - Reserved
												 */
			__IO     uint16_t HIRD                : 4;   /* This is the Host Initiated Resume Duration.This value is the minimum time the host will
												 * drive resume on the Bus. The value in this register corresponds to an actual resume time
												 * of:
												 * Resume Time = 50us + HIRD * 75us.This results a range 50us to 1200us.
												 */
			__IO     uint16_t RmtWak              : 1;   /* This bit is the remote wakeup enable bit:
												 * RmtWak = 1'b0:Remote wakeup is not enabled.
												 * RmtWak = 1'b1:Remote wakeup is enabled.
												 * This bit is applied on a temporary basis only and is only applied to the current suspend
												 * state.After the current suspend cycle,the remote wakeup capability that was negotiated
												 * upon enumeration will apply.
												 */
			__IO     uint16_t reserved9_11        : 3;   /* Reserved;Always returns 0 on read */
			__IO     uint16_t EndPoint            : 4;   /* This is the EndPnt that in the Token Packet of the LPM transaction. -*/
		} LPM_ATTR_b;
	};
	union
	{
		__IO    uint8_t     LPM_CNTRL;
	    struct
	    {
			__IO    uint8_t lpmxmt              : 1;
			__IO    uint8_t lpmres              : 1;
			__IO    uint8_t lpmen               : 2;
			__IO    uint8_t lpmnak              : 1;
			__IO    uint8_t reserved5_7         : 3;
	    } LPM_CNTRL_DEV_b;
	    struct
	    {
	    	__IO    uint8_t lpmxmt              : 1;
	    	__IO    uint8_t lpmres              : 1;
	    	__IO    uint8_t reserved2_7         : 6;
	    } LPM_CNTRL_HOST_b;
	};
	union
	{
	    __IO    uint8_t     LPM_INTREN;
	    struct
	    {
	    	__IO    uint8_t lpmxmt              : 1;
	    	__IO    uint8_t lpmres              : 1;
	    	__IO    uint8_t reserved2_7         : 6;
	    } LPM_INTREN_b;
	};
	union
	{
	    __IO     uint8_t     LPM_INTR;
	    struct
	    {
	    	__IO     uint8_t lpmst               : 1;
	    	__IO     uint8_t lpmny               : 1;
	    	__IO     uint8_t lpmack              : 1;
	    	__IO     uint8_t lpmnc               : 1;
	    	__IO     uint8_t lpmres              : 1;
	    	__IO     uint8_t lpmerr              : 1;
	    	__IO     uint8_t reserved6_7         : 2;
	    } LPM_INTR_DEV_b;
	    struct
	    {
	    	__IO     uint8_t lpmst               : 1;
	    	__IO     uint8_t lpmny               : 1;
	    	__IO     uint8_t lpmack              : 1;
	    	__IO     uint8_t lpmnc               : 1;
	    	__IO     uint8_t lpmres              : 1;
	    	__IO     uint8_t reserved5_7         : 3;
	    } LPM_INTR_HOST_b;
	};
    union
	{
        __IO    uint8_t     LPM_FADDR;      // Relavant in Host mode only.
        struct
        {
        	__IO    uint8_t function_address    : 7;
        	__IO    uint8_t reserved7           : 1;
        } LPM_FADDR_b;
    };

}USB_TypeDef;

#define USB_OTG ( (USB_TypeDef *) USB_BASE )
typedef struct
{
	const USB_TypeDef *RegBase;
	const int IrqLine;
	USB_EndpointCtrlStruct EpCtrl[USB_EP_MAX];
	uint32_t RxData[USB_FIFO_DW_DAX];
	PV_Union pRxData;
	uint8_t IsConnect;
	uint8_t IsHost;
	uint8_t NewDeviceAddress;
}USB_HWCtrlStruct;

static USB_HWCtrlStruct prvUSB =
{
		.RegBase = USB_BASE,
		.IrqLine = USB_IRQn,
};

static uint8_t USB_OTG_FifosizeReg(uint16_t fifosiz)
{
    uint8_t register_value = 0;
    switch (fifosiz)
    {
	case 8:
		register_value = 0;
		break;
	case 16:
		register_value = 1;
		break;
	case 32:
		register_value = 2;
		break;
	case 64:
		register_value = 3;
		break;
	case 128:
		register_value = 4;
		break;
    }
    return register_value;
}

static void prvUSB_IrqHandle(int32_t IrqLine, void *pData)
{
	uint32_t USB_ID = (uint32_t)pData;
	uint32_t i;
	uint32_t Count32b;
	uint16_t RxLen;
	uint16_t TxBit = USB_OTG->INTRTX;
	uint16_t RxBit = USB_OTG->INTRRX;
	uint8_t StateBit = USB_OTG->INTRUSB;
	uint8_t EpIndex = 1;
	USB_OTG->INTRUSB = 0;
	USB_OTG->INTRRX = 0;
	USB_OTG->INTRTX = 0;
	if (prvUSB.IsHost || USB_OTG->DEVCTL_b.host_mode)
	{
		;
	}
	else
	{

		if (StateBit & 0x1)
		{
			USB_StackDeviceBusChange(USB_ID, USBD_BUS_TYPE_SUSPEND);
		}
		if (StateBit & 0x2)
		{
			USB_StackDeviceBusChange(USB_ID, USBD_BUS_TYPE_RESUME);
			USB_OTG->POWER_b.resume = 1;
		}
		if (StateBit & 0x4)
		{
			USB_OTG->FADDR = 0;
			USB_OTG->INDEX = 0;
			USB_FlushFifo(&prvUSB, 0, 0);
			for(i = 1; i < 8; i++)
			{
				USB_FlushFifo(&prvUSB,i, 0);
				USB_FlushFifo(&prvUSB,i, 1);
			}
			USB_SetDeviceEPStatus(&prvUSB, 0, 0, USB_EP_STATE_ACK);
			USB_StackDeviceBusChange(USB_ID, USBD_BUS_TYPE_RESET);
		}
		if (StateBit & 0x8)
		{
			USB_StackDeviceBusChange(USB_ID, USBD_BUS_TYPE_NEW_SOF);
		}
		if (StateBit & 0x20)
		{
			for(i = 0; i < 8; i++)
			{
				memset(&prvUSB.EpCtrl[i].TxBuf, 0, sizeof(Buffer_Struct));
			}
			USB_StackDeviceBusChange(USB_ID, USBD_BUS_TYPE_DISCONNECT);
		}
		if (TxBit & 0x01)
		{
			if (USB_OTG->CSR0L_DEV_b.sent_stall)
			{
				USB_SetDeviceEPStatus(&prvUSB, 0, 0, USB_EP_STATE_ACK);
			}
			if (USB_OTG->CSR0L_DEV_b.setup_end)
			{
				USB_OTG->CSR0L_DEV_b.serviced_setupend = 1;
			}
            if (prvUSB.NewDeviceAddress & 0x80)
            {
            	USB_OTG->FADDR = prvUSB.NewDeviceAddress & 0x7f;
            	prvUSB.NewDeviceAddress = 0;
            }
			if (USB_OTG->CSR0L_DEV_b.rx_pkt_rdy)
			{
				RxLen = USB_OTG->COUNT0_b.ep0_rx_count;
				if (RxLen)
				{
					Count32b = RxLen >> 2;
				    for (i = 0; i < Count32b; i++)
				    {
				    	prvUSB.RxData[i] = USB_OTG->FIFOX[0].dword;
				    }
				    for (i = Count32b * 4; i < RxLen; i++)
				    {
				    	prvUSB.pRxData.pu8[i] = USB_OTG->FIFOX[0].byte;
				    }
				    USB_StackPutRxData(USB_ID, 0, prvUSB.pRxData.pu8, RxLen);
				}
				USB_OTG->CSR0L_DEV_b.serviced_rxpktrdy = 1;
			    USB_StackAnalyzeDeviceEpRx(USB_ID, 0);
			}
            else if (!USB_OTG->CSR0L_DEV_b.tx_pkt_rdy)
            {
            	USB_DeviceXfer(&prvUSB, 0);
            }

		}
		else if (TxBit)
		{
			TxBit >>= 1;
			EpIndex = 1;
			while(TxBit)
			{
				if (TxBit & 0x01)
				{
					if (!USB_OTG->CSR[EpIndex].TXCSRL_DEV_b.tx_pkt_rdy)
					{
						USB_DeviceXfer(&prvUSB, EpIndex);
					}
					USB_OTG->CSR[EpIndex].TXCSRL_DEV_b.sent_stall = prvUSB.EpCtrl[EpIndex].INSTATUS_b.Halt?1:0;
					USB_OTG->CSR[EpIndex].TXCSRL_DEV_b.send_stall = 0;
					USB_OTG->CSR[EpIndex].TXCSRL_DEV_b.under_run = 0;
				}
				TxBit >>= 1;
				EpIndex++;
			}
		}
		if (RxBit)
		{
			EpIndex = 1;
			RxBit >>= 1;
			while(RxBit)
			{
				if (RxBit & 0x01)
				{
					if (USB_OTG->CSR[EpIndex].RXCSRL_DEV_b.rx_pkt_rdy)
					{
						RxLen = USB_OTG->CSR[EpIndex].RXCOUNT_b.ep_rx_count;
						if (RxLen)
						{
							Count32b = RxLen >> 2;
						    for (i = 0; i < Count32b; i++)
						    {
						    	prvUSB.RxData[i] = USB_OTG->FIFOX[EpIndex].dword;
						    }
						    for (i = Count32b * 4; i < RxLen; i++)
						    {
						    	prvUSB.pRxData.pu8[i] = USB_OTG->FIFOX[EpIndex].byte;
						    }
						    USB_StackPutRxData(USB_ID, EpIndex, prvUSB.pRxData.pu8, RxLen);
						}
					}
					USB_OTG->CSR[EpIndex].RXCSRL = 0;
					USB_OTG->CSR[EpIndex].RXCSRL_DEV_b.sent_stall = prvUSB.EpCtrl[EpIndex].OUTSTATUS_b.Halt?1:0;
					USB_StackAnalyzeDeviceEpRx(USB_ID, EpIndex);
				}
				RxBit >>= 1;
				EpIndex++;
			}

		}
	}
}

static int prvUSB_SetupEPFifo(HANDLE hUSB)
{
	USB_HWCtrlStruct *hwUSB = (USB_HWCtrlStruct *)hUSB;
	uint8_t i;
	uint8_t Len;
	uint16_t FifoStart = (64 >> 3);
	uint16_t UseFifo = 64;
	//ep0使用默认的64byte

	USB_OTG->INDEX = 0;
	USB_OTG->TXFIFOSZ = 3;
	USB_OTG->RXFIFOSZ = 3;
	USB_OTG->TXFIFOADD = 0;
	USB_OTG->RXFIFOADD = 0;
	USB_OTG->CSR0H_DEV_b.flush_fifo = 1;	//刷新EP0的FIFO
	hwUSB->EpCtrl[0].MaxPacketLen = 64;
	for(i = 1; i < USB_EP_MAX; i++)
	{
		USB_OTG->INDEX = i;
		if (hwUSB->EpCtrl[i].ToDeviceEnable)
		{
			Len = USB_OTG_FifosizeReg(hwUSB->EpCtrl[i].MaxPacketLen);
			USB_OTG->CSR[i].RXMAXP = hwUSB->EpCtrl[i].MaxPacketLen;
			USB_OTG->RXFIFOADD = FifoStart;
			USB_OTG->RXFIFOSZ = Len;
			USB_OTG->CSR[i].RXCSRL = (1 << 4);
			//DBG("%d,%d,%x,%d,%x", i, USB_OTG->CSR[i].RXMAXP, USB_OTG->RXFIFOADD, USB_OTG->RXFIFOSZ, USB_OTG->CSR[i].RXCSRL);
			FifoStart += (hwUSB->EpCtrl[i].MaxPacketLen >> 3);
			UseFifo += hwUSB->EpCtrl[i].MaxPacketLen;
		}
		if (UseFifo > 512)
		{
			DBG("to much fifo!");
			return -1;
		}
		if (hwUSB->EpCtrl[i].ToHostEnable)
		{
			USB_OTG->CSR[i].TXMAXP = hwUSB->EpCtrl[i].MaxPacketLen;
			USB_OTG->TXFIFOADD = FifoStart;
			USB_OTG->TXFIFOSZ = Len;
			USB_OTG->CSR[i].TXCSRL = (1 << 3);
			//DBG("%d,%d,%x,%d,%x", i, USB_OTG->CSR[i].TXMAXP, USB_OTG->TXFIFOADD, USB_OTG->TXFIFOSZ, USB_OTG->CSR[i].TXCSRL);
			FifoStart += (hwUSB->EpCtrl[i].MaxPacketLen >> 3);
			UseFifo += hwUSB->EpCtrl[i].MaxPacketLen;
		}
		if (UseFifo > 512)
		{
			DBG("to much fifo!");
			return -1;
		}
	}
	USB_OTG->INDEX = 0;
	return 0;
}

void USB_GlobalInit(void)
{
	USB_HWCapsStruct Caps;


    ISR_SetHandler(prvUSB.IrqLine, prvUSB_IrqHandle, USB_ID0);
#ifdef __BUILD_OS__
	ISR_SetPriority(prvUSB.IrqLine, IRQ_LOWEST_PRIORITY);
#else
	ISR_SetPriority(prvUSB.IrqLine, 7);
#endif
	prvUSB.IsConnect = 0;
	Caps.EpBufMaxLen = 4096;
	Caps.Feature = 0;
	Caps.FEATURE_b.FullSpeed = 1;
	Caps.CtrlMode = USB_MODE_DUAL;
	USB_StackSetControl(USB_ID0, &prvUSB, prvUSB.EpCtrl, &Caps);
	USB_StackSetDeviceSpeed(USB_ID0, USB_DEVICE_SPEED_FULL_SPEED);
	USB_OTG->INTRRXE = 0;
	USB_OTG->INTRTXE = 0;
	USB_OTG->INTRUSBE = 0;
	prvUSB.pRxData.pu32 = prvUSB.RxData;
	SYSCTRL->CG_CTRL2 &= ~SYSCTRL_AHBPeriph_USB;

}

void USB_PowerOnOff(HANDLE hUSB, uint8_t OnOff)
{
	if (OnOff)
	{
		SYSCTRL->CG_CTRL2 |= SYSCTRL_AHBPeriph_USB;
	}
	else
	{
		SYSCTRL->CG_CTRL2 &= ~SYSCTRL_AHBPeriph_USB;
	}
}

void USB_Stop(HANDLE hUSB)
{
	uint8_t dummy;
	USB_HWCtrlStruct *hwUSB = (USB_HWCtrlStruct *)hUSB;
	ISR_OnOff(hwUSB->IrqLine, 0);
	USB_OTG->POWER = 0;
	USB_OTG->INTRRXE = 0;
	USB_OTG->INTRTXE = 0;
	USB_OTG->INTRUSBE = 0;
	USB_OTG->INTRTX = 0;
	USB_OTG->INTRRX = 0;
	USB_OTG->INTRUSB = 0;
	dummy = USB_OTG->INTRUSB;
}

void USB_ResetStart(HANDLE hUSB)
{
	SYSCTRL->LOCK_R &= ~SYSCTRL_USB_RESET;
    SYSCTRL->SOFT_RST2 |= SYSCTRL_USB_RESET;
    SYSCTRL->LOCK_R |= SYSCTRL_USB_RESET;
}

void USB_ResetEnd(HANDLE hUSB)
{
	SYSCTRL->LOCK_R &= ~SYSCTRL_USB_RESET;
    SYSCTRL->SOFT_RST2 &= ~SYSCTRL_USB_RESET;
    SYSCTRL->LOCK_R |= SYSCTRL_USB_RESET;
}

void USB_SetWorkMode(HANDLE hUSB, uint8_t Mode)
{
	USB_HWCtrlStruct *hwUSB = (USB_HWCtrlStruct *)hUSB;
	USBPHY_CR1_TypeDef CR1;
	USBPHY_CR3_TypeDef CR3;
	CR1.d32 = SYSCTRL->USBPHY_CR1;
	CR1.b.commononn = 0;
	CR1.b.stop_ck_for_suspend = 0;
	SYSCTRL->USBPHY_CR1 = CR1.d32;

	switch (Mode)
	{
	case USB_MODE_HOST:
		USB_OTG->POWER = 1;
		USB_OTG->DEVCTL |= (1 << 0)|(1 << 2);
		CR3.d32 = SYSCTRL->USBPHY_CR3;
		CR3.b.idpullup = 1;
		SYSCTRL->USBPHY_CR3 = CR3.d32;
		hwUSB->IsHost = 1;
		break;
	default:
		USB_OTG->DEVCTL &= ~((1 << 0)|(1 << 2));
		USB_OTG->POWER = 1|(1 << 6);
		CR3.d32 = SYSCTRL->USBPHY_CR3;
		CR3.b.idpullup = 0;
		SYSCTRL->USBPHY_CR3 = CR3.d32;
		hwUSB->IsHost = 0;
		break;
	}
}

void USB_SetDeviceAddress(HANDLE hUSB, uint8_t Address)
{
	prvUSB.NewDeviceAddress = 0x80 | Address;
}

int USB_ReInitEpCfg(HANDLE hUSB)
{
	return -1;
}

int USB_InitEpCfg(HANDLE hUSB)
{
	return prvUSB_SetupEPFifo(hUSB);
}


void USB_Start(HANDLE hUSB)
{
	USB_HWCtrlStruct *hwUSB = (USB_HWCtrlStruct *)hUSB;
	USB_OTG->INTRUSBE = 0xff;
	USB_OTG->INTRUSBE_b.en_sof = 0;
	USB_OTG->INTRTXE = 0xff;
	USB_OTG->INTRRXE = 0xfe;
	ISR_OnOff(hwUSB->IrqLine, 1);
}

void USB_SendZeroPacket(HANDLE hUSB, uint8_t EpIndex)
{
	if (EpIndex)
	{
		USB_OTG->CSR[EpIndex].TXCSRL_DEV_b.tx_pkt_rdy = 1;
	}
	else
	{
		USB_OTG->CSR0L_DEV_b.tx_pkt_rdy = 1;
	}
}

void USB_DeviceXferStop(HANDLE hUSB, uint8_t EpIndex)
{
	USB_HWCtrlStruct *hwUSB = (USB_HWCtrlStruct *)hUSB;
	USB_OTG->INTRTXE &= ~(1 << EpIndex);
	USB_FlushFifo(hUSB, EpIndex, 0);
	USB_OTG->CSR[EpIndex].TXCSRL_DEV_b.send_stall = 0;
	USB_OTG->CSR[EpIndex].TXCSRL_DEV_b.sent_stall = 0;
	USB_OTG->CSR[EpIndex].TXCSRL_DEV_b.under_run = 0;
	USB_OTG->INTRTXE |= (1 << EpIndex);
}

void USB_EpIntOnOff(HANDLE hUSB, uint8_t EpIndex, uint8_t IsToDevice, uint8_t OnOff)
{
	USB_HWCtrlStruct *hwUSB = (USB_HWCtrlStruct *)hUSB;
	if (IsToDevice)
	{
		if (OnOff)
		{
			USB_OTG->INTRRXE |= (1 << EpIndex);
		}
		else
		{
			USB_OTG->INTRRXE &= ~(1 << EpIndex);
		}
	}
	else
	{
		if (OnOff)
		{
			USB_OTG->INTRTXE |= (1 << EpIndex);
		}
		else
		{
			USB_OTG->INTRTXE &= ~(1 << EpIndex);
		}
	}
}

void USB_DeviceXfer(HANDLE hUSB, uint8_t EpIndex)
{
	USB_HWCtrlStruct *hwUSB = (USB_HWCtrlStruct *)hUSB;
	USB_EndpointCtrlStruct *pEpCtrl = &hwUSB->EpCtrl[EpIndex];
	USB_EndpointDataStruct EpData;
	uint16_t TxLen, i;


	if (pEpCtrl->TxBuf.Data)
	{
		if (pEpCtrl->TxBuf.Pos >= pEpCtrl->TxBuf.MaxLen)
		{
			if (pEpCtrl->NeedZeroPacket)
			{
//				DBG("Ep%d %d %d %d need send 0 packet", EpIndex,
//						pEpCtrl->ForceZeroPacket, pEpCtrl->TxBuf.Pos, pEpCtrl->XferMaxLen);
				if (!pEpCtrl->TxZeroPacket)
				{
					pEpCtrl->TxZeroPacket = 1;
					if (EpIndex)
					{
						USB_OTG->CSR[EpIndex].TXCSRL_DEV_b.tx_pkt_rdy = 1;
					}
					else
					{
						USB_OTG->CSR0L_DEV_b.tx_pkt_rdy = 1;
					}
				}
				else
				{
					DBG("!");
				}

			}
			goto XFER_DONE;
		}
		else
		{
			pEpCtrl->TxZeroPacket = 0;
			if ((pEpCtrl->TxBuf.MaxLen - pEpCtrl->TxBuf.Pos) > pEpCtrl->MaxPacketLen)
			{
				TxLen = pEpCtrl->MaxPacketLen;
			}
			else
			{
				if (pEpCtrl->ForceZeroPacket)
				{
					pEpCtrl->NeedZeroPacket = 1;
				}
				if ((pEpCtrl->TxBuf.MaxLen - pEpCtrl->TxBuf.Pos) == pEpCtrl->MaxPacketLen)
				{
					if ( pEpCtrl->TxBuf.MaxLen < pEpCtrl->XferMaxLen )
					{
						pEpCtrl->NeedZeroPacket = 1;
					}
				}
				TxLen = pEpCtrl->TxBuf.MaxLen - pEpCtrl->TxBuf.Pos;
			}


			for(i = pEpCtrl->TxBuf.Pos; i < pEpCtrl->TxBuf.Pos + TxLen; i++)
			{
				USB_OTG->FIFOX[EpIndex].byte = pEpCtrl->TxBuf.Data[i];
			}
			pEpCtrl->TxBuf.Pos += TxLen;
			if (EpIndex)
			{
				USB_OTG->CSR[EpIndex].TXCSRL_DEV_b.tx_pkt_rdy = 1;
			}
			else
			{
				USB_OTG->CSR0L_DEV_b.tx_pkt_rdy = 1;
			}
		}
	}
	return;
XFER_DONE:
	memset(&pEpCtrl->TxBuf, 0, sizeof(Buffer_Struct));
	if (EpIndex)
	{
		memset(&EpData, 0, sizeof(EpData));
		EpData.USB_ID = USB_ID0;
		EpData.EpIndex = EpIndex;
		pEpCtrl->CB(&EpData, pEpCtrl->pData);
	}
	else
	{
		USB_StackDeviceEp0TxDone(USB_ID0);
	}
}

void USB_SetDeviceNoDataSetup(HANDLE hUSB)
{
	{
		USB_OTG->CSR0L_DEV_b.data_end = 1;
	}
}

void USB_FlushFifo(HANDLE hUSB, uint8_t EpIndex, uint8_t IsToDevice)
{
	if (EpIndex)
	{
		if (IsToDevice)
		{
			USB_OTG->CSR[EpIndex].RXCSRL = (1 << 4);
		}
		else
		{

			USB_OTG->CSR[EpIndex].TXCSRL = (1 << 3);

		}

	}
	else
	{
		if (USB_OTG->CSR0L_DEV_b.rx_pkt_rdy || USB_OTG->CSR0L_DEV_b.tx_pkt_rdy)
		{
			USB_OTG->CSR0H_DEV_b.flush_fifo = 1;
			USB_OTG->CSR0L_DEV_b.serviced_rxpktrdy = 1;
			USB_OTG->CSR0L_DEV_b.tx_pkt_rdy        = 0;
		}
	}
}

/**
* @brief  returns the EP Status
* @param  pdev : Selected device
*         ep : endpoint structure
* @retval : EP status
*/

uint8_t USB_GetDeviceEPStatus(HANDLE hUSB, uint8_t Index, uint8_t IsToDevice)
{
	if (Index)
    {
	    if (IsToDevice)
	    {

    		if (USB_OTG->CSR[Index].RXCSRL_DEV_b.sent_stall)
    		{
    			return USB_EP_STATE_STALL;
    		}
    		if (USB_OTG->CSR[Index].RXCSRL_DEV_b.data_error || USB_OTG->CSR[Index].RXCSRL_DEV_b.over_run)
    		{
    			return USB_EP_STATE_NAK;
    		}
    		return USB_EP_STATE_ACK;
    	}
	    else
	    {
    		if (USB_OTG->CSR[Index].TXCSRL_DEV_b.sent_stall)
    		{
    			return USB_EP_STATE_STALL;
    		}
    		if (USB_OTG->CSR[Index].TXCSRL_DEV_b.under_run || USB_OTG->CSR[Index].TXCSRL_DEV_b.tx_pkt_rdy)
    		{
    			return USB_EP_STATE_NAK;
    		}
    		return USB_EP_STATE_ACK;
	    }
    }
    else
    {
		if (USB_OTG->CSR0L_DEV_b.sent_stall)
		{
			return USB_EP_STATE_STALL;
		}
		return USB_EP_STATE_ACK;
    }
}

/**
* @brief  Set the EP Status
* @param  pdev : Selected device
*         Status : new Status
*         ep : EP structure
* @retval : None
*/
void USB_SetDeviceEPStatus (HANDLE hUSB, uint8_t Index, uint8_t IsToDevice, uint8_t Status)
{
	if (Index)
	{
		if (IsToDevice)
		{
			switch(Status)
			{
			case USB_EP_STATE_DISABLE:
			case USB_EP_STATE_NAK:
			case USB_EP_STATE_NYET:
				break;
			case USB_EP_STATE_STALL:
				DBG("%d", Index);
				USB_OTG->CSR[Index].RXCSRL_DEV_b.send_stall = 1;
				break;
			case USB_EP_STATE_ENABLE:
			case USB_EP_STATE_ACK:
				USB_OTG->CSR[Index].RXCSRL_DEV_b.send_stall = 0;
				USB_OTG->CSR[Index].RXCSRL_DEV_b.sent_stall = 0;
				USB_OTG->CSR[Index].RXCSRL_DEV_b.over_run = 0;
				USB_OTG->CSR[Index].RXCSRL_DEV_b.data_error = 0;
				break;
			}
		}
		else
		{
			switch(Status)
			{
			case USB_EP_STATE_DISABLE:
			case USB_EP_STATE_NAK:
			case USB_EP_STATE_NYET:
				break;
			case USB_EP_STATE_STALL:
				DBG("%d", Index);
				USB_OTG->CSR[Index].TXCSRL_DEV_b.send_stall = 1;
				break;
			case USB_EP_STATE_ENABLE:
			case USB_EP_STATE_ACK:
				USB_OTG->CSR[Index].TXCSRL_DEV_b.send_stall = 0;
				USB_OTG->CSR[Index].TXCSRL_DEV_b.sent_stall = 0;
				USB_OTG->CSR[Index].TXCSRL_DEV_b.under_run = 0;
				break;
			}
		}
	}
	else
	{
		switch(Status)
		{
		case USB_EP_STATE_DISABLE:
		case USB_EP_STATE_NYET:
		case USB_EP_STATE_NAK:
			break;
		case USB_EP_STATE_STALL:
			USB_OTG->CSR0L_DEV_b.send_stall = 1;
			break;
		case USB_EP_STATE_ACK:
		case USB_EP_STATE_ENABLE:
			USB_OTG->CSR0L_DEV_b.send_stall = 0;
			USB_OTG->CSR0L_DEV_b.sent_stall = 0;
			break;
		}
	}
}

void USB_ResumeStart(HANDLE hUSB)
{
	USB_OTG->POWER_b.resume = 1;
}

void USB_ResumeEnd(HANDLE hUSB)
{
	USB_OTG->POWER_b.resume = 0;
}

int32_t USB_SetISOCHDelay(HANDLE hUSB, uint16_t DelayNS)
{
	return -1;
}

int32_t USB_ExitLatency(HANDLE hUSB, uint8_t Config[6])
{
	return -1;
}

#ifdef __BUILD_APP__
INIT_DRV_EXPORT(USB_GlobalInit, "0");
#endif
