Merge branch 'ch32_drv'
This commit is contained in:
		
						commit
						1737696a8b
					
				
							
								
								
									
										646
									
								
								driver/ch32/usb_drv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										646
									
								
								driver/ch32/usb_drv.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,646 @@
 | 
			
		||||
#include "usb_drv.h"
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "flatUSB_config.h"
 | 
			
		||||
#include "usb_driver_common.h"
 | 
			
		||||
 | 
			
		||||
#include FLATUSB_DESCRIPTOR_HEADER
 | 
			
		||||
 | 
			
		||||
#include "usb_common.h"
 | 
			
		||||
 | 
			
		||||
#include "ch32f20x_usb.h"
 | 
			
		||||
 | 
			
		||||
#ifndef SET_BIT
 | 
			
		||||
#define SET_BIT(r, b) (r) |= (b)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef GET_BIT
 | 
			
		||||
#define GET_BIT(r, b) (((r) & (b)) != 0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef CLEAR_BIT
 | 
			
		||||
#define CLEAR_BIT(r, b) (r) &= ~(b)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __weak
 | 
			
		||||
#define __weak __attribute__((weak))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// ------------------------
 | 
			
		||||
 | 
			
		||||
// combined buffer: TX1 | RX1 | TX2 | RX2 (TODO: ennek még utána kell nézni)
 | 
			
		||||
 | 
			
		||||
#define USB_EP_TX_BUF_SIZE (64)                                                      ///< Transmit buffer size
 | 
			
		||||
#define USB_EP_RX_BUF_SIZE (64)                                                      ///< Receive buffer size
 | 
			
		||||
#define USB_EP_COMBINED_BUF_SIZE ((USB_EP_TX_BUF_SIZE + USB_EP_RX_BUF_SIZE) * 2)     ///< Combined buffer size in a single direction
 | 
			
		||||
#define USB_EP_SUMMED_BUF_SIZE (USB_EP_COMBINED_BUF_SIZE * USB_NUM_OF_ENDPOINTS * 2) ///< Summed size for each endpoint in each direction
 | 
			
		||||
 | 
			
		||||
static USBDRV_GlobalState gs;                           ///< Global USB state
 | 
			
		||||
static uint8_t buf[USB_EP_SUMMED_BUF_SIZE] DWORD_ALIGN; ///< Transmit/Receive buffer
 | 
			
		||||
static UsbDrv_IN_cb cbs[USB_NUM_OF_ENDPOINTS];          ///< Callbacks for IN completion
 | 
			
		||||
 | 
			
		||||
// FIXME: ez lehet, hogy pont fordítva van...
 | 
			
		||||
#define USB_EP_GET_EP0_BUFFER() (gs.buf)
 | 
			
		||||
#define USB_EP_GET_TX_BUFFER(ep) (gs.buf + ((ep) * USB_EP_COMBINED_BUF_SIZE))
 | 
			
		||||
#define USB_EP_GET_RX_BUFFER(ep) (gs.buf + ((ep) * USB_EP_COMBINED_BUF_SIZE) + USB_EP_TX_BUF_SIZE)
 | 
			
		||||
 | 
			
		||||
/** \cond false */
 | 
			
		||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
 | 
			
		||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
 | 
			
		||||
/** \endcond */
 | 
			
		||||
 | 
			
		||||
// ------------------------
 | 
			
		||||
 | 
			
		||||
void usbdrv_register_IN_complete_cb(uint8_t ep, UsbDrv_IN_cb cb) {
 | 
			
		||||
    cbs[ep] = cb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ------------------------
 | 
			
		||||
 | 
			
		||||
static UsbDrv_DrvIntf drvIntf;
 | 
			
		||||
 | 
			
		||||
void usbdrv_init_intf() {
 | 
			
		||||
    drvIntf.init = usbdrv_init;
 | 
			
		||||
    drvIntf.reset = usbdrv_reset;
 | 
			
		||||
    drvIntf.stall = usbdrv_stall_endpoint;
 | 
			
		||||
    drvIntf.arm_IN = usbdrv_arm_IN_endpoint;
 | 
			
		||||
    drvIntf.arm_OUT = usbdrv_arm_OUT_endpoint;
 | 
			
		||||
    drvIntf.set_address = usbdrv_set_address;
 | 
			
		||||
    drvIntf.set_config = usbdrv_fetch_endpoint_configuration;
 | 
			
		||||
    drvIntf.autoarm = usbdrv_autoarm_OUT_endpoint;
 | 
			
		||||
    drvIntf.en_ep_irq = usbdrv_enable_endpoint_interrupt;
 | 
			
		||||
    drvIntf.reg_IN_cb = usbdrv_register_IN_complete_cb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UsbDrv_DrvIntf *usbdrv_get_intf() {
 | 
			
		||||
    return &drvIntf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ------------------------
 | 
			
		||||
 | 
			
		||||
// issue a reset
 | 
			
		||||
static void usbdrv_hw_reset() {
 | 
			
		||||
    SET_BIT(USBG->BASE_CTRL, USBFS_UC_RESET_SIE);   // assert reset
 | 
			
		||||
    USB_DELAY(1);                                   // insert some delay
 | 
			
		||||
    CLEAR_BIT(USBG->BASE_CTRL, USBFS_UC_RESET_SIE); // release reset
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// initialize USB peripheral
 | 
			
		||||
void usbdrv_periph_init(bool reset) {
 | 
			
		||||
    if (!reset) {
 | 
			
		||||
        // enable USB clock
 | 
			
		||||
        USB_CLOCK_ENABLE();
 | 
			
		||||
 | 
			
		||||
        // trigger a reset (FIXME: biztos jó ez így?)
 | 
			
		||||
        usbdrv_hw_reset();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // turn off the transciever
 | 
			
		||||
    usbdrv_power_and_connect(false);
 | 
			
		||||
 | 
			
		||||
    // select device mode with internal pullups
 | 
			
		||||
    CLEAR_BIT(USBG->BASE_CTRL, USBFS_UC_HOST_MODE); // device mode
 | 
			
		||||
    SET_BIT(USBG->BASE_CTRL, USBFS_UC_SYS_CTRL3);   // pullup activation
 | 
			
		||||
 | 
			
		||||
    // set Full-Speed operation (TODO: lehet, hogy a low-speed-et is érdemes megírni)
 | 
			
		||||
    CLEAR_BIT(USBG->BASE_CTRL, USBFS_UC_LOW_SPEED); // (global)
 | 
			
		||||
    CLEAR_BIT(USBG->UDEV_CTRL, USBFS_UD_LOW_SPEED); // (device)
 | 
			
		||||
 | 
			
		||||
    // set automatic NAK reporting
 | 
			
		||||
    SET_BIT(USBG->BASE_CTRL, USBFS_UC_INT_BUSY);
 | 
			
		||||
 | 
			
		||||
    // clear all interrupts
 | 
			
		||||
    USBG->INT_FG = 0xFF;
 | 
			
		||||
 | 
			
		||||
    // allow specific interrupts
 | 
			
		||||
    uint32_t intmask =
 | 
			
		||||
        USBFS_UIE_BUS_RST |  // Bus reset
 | 
			
		||||
        USBFS_UIE_TRANSFER | // Transfer complete interrupt
 | 
			
		||||
        USBFS_UIE_SUSPEND |  // Bues suspend or wakeup interrupt
 | 
			
		||||
        USBFS_UIE_FIFO_OV;   // FIFO overflow interrupt
 | 
			
		||||
    USBG->INT_EN = intmask;
 | 
			
		||||
 | 
			
		||||
    if (!reset) {
 | 
			
		||||
        // flush Tx and Rx FIFOs
 | 
			
		||||
        usbdrv_clear_all_fifos();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// initialize global state
 | 
			
		||||
void usbdrv_init_global_state() {
 | 
			
		||||
    // clear state
 | 
			
		||||
    memset(&gs, 0, sizeof(USBDRV_GlobalState));
 | 
			
		||||
 | 
			
		||||
    // clear IN complete callbacks
 | 
			
		||||
    memset(&cbs, 0, sizeof(UsbDrv_IN_cb) * USB_NUM_OF_ENDPOINTS);
 | 
			
		||||
 | 
			
		||||
    // initialize receive buffer
 | 
			
		||||
    gs.buf = buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// initialize USB subsystem
 | 
			
		||||
void usbdrv_init() {
 | 
			
		||||
    USB_IRQ_DISABLE(USB_IRQ_N); // disable USB interrupts
 | 
			
		||||
 | 
			
		||||
    usbdrv_init_global_state();
 | 
			
		||||
    usbdrv_init_intf();
 | 
			
		||||
    usbdrv_gpio_init();
 | 
			
		||||
    usbdrv_periph_init(false);
 | 
			
		||||
    usbdrv_initial_ep0_setup();
 | 
			
		||||
    usbdrv_power_and_connect(true);
 | 
			
		||||
 | 
			
		||||
    USB_IRQ_SET_PRIORITY(USB_IRQ_N, USB_IRQ_PRIORITY);
 | 
			
		||||
    USB_IRQ_ENABLE(USB_IRQ_N);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void usbdrv_reset() {
 | 
			
		||||
    USB_IRQ_DISABLE(USB_IRQ_N); // disable USB interrupts
 | 
			
		||||
 | 
			
		||||
    usbdrv_hw_reset(); // hardware reset
 | 
			
		||||
    usbdrv_init_global_state();
 | 
			
		||||
    usbdrv_periph_init(true);
 | 
			
		||||
    usbdrv_initial_ep0_setup();
 | 
			
		||||
    usbdrv_power_and_connect(true);
 | 
			
		||||
 | 
			
		||||
    USB_IRQ_SET_PRIORITY(USB_IRQ_N, USB_IRQ_PRIORITY);
 | 
			
		||||
    USB_IRQ_ENABLE(USB_IRQ_N);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// connect to or disconnect from the bus
 | 
			
		||||
void usbdrv_power_and_connect(bool en) {
 | 
			
		||||
    if (en) {                                           // ON
 | 
			
		||||
        SET_BIT(USBG->BASE_CTRL, USBFS_UC_DEV_PU_EN);   // enable USB device and internal pull-ups (global)
 | 
			
		||||
        SET_BIT(USBG->UDEV_CTRL, USBFS_UD_PORT_EN);     // enable USB device physical port (device)
 | 
			
		||||
        SET_BIT(USBG->BASE_CTRL, USBFS_UC_DMA_EN);      // enable DMA operation and interrupts
 | 
			
		||||
    } else {                                            // OFF
 | 
			
		||||
        CLEAR_BIT(USBG->BASE_CTRL, USBFS_UC_DEV_PU_EN); // disable...
 | 
			
		||||
        CLEAR_BIT(USBG->UDEV_CTRL, USBFS_UD_PORT_EN);   // ...
 | 
			
		||||
        CLEAR_BIT(USBG->BASE_CTRL, USBFS_UC_DMA_EN);    // ...
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// -------------------
 | 
			
		||||
 | 
			
		||||
// clear all FIFOs
 | 
			
		||||
void usbdrv_clear_all_fifos() {
 | 
			
		||||
    SET_BIT(USBG->BASE_CTRL, USBFS_UC_CLR_ALL);
 | 
			
		||||
    USB_DELAY(1);
 | 
			
		||||
    CLEAR_BIT(USBG->BASE_CTRL, USBFS_UC_CLR_ALL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ---------------------
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    volatile uint8_t *UEP_MOD;          ///< EP mode control register
 | 
			
		||||
    uint8_t RX_EN;                      ///< EP receive enable flag
 | 
			
		||||
    uint8_t TX_EN;                      ///< EP transmit enable flag
 | 
			
		||||
    uint8_t BUF_MOD;                    ///< EP buffer mode flag
 | 
			
		||||
    volatile uint32_t *BUF_START_ADDR;  ///< EP buffer start address
 | 
			
		||||
    volatile uint16_t *TRANSMIT_LENGTH; ///< EP transmit length register
 | 
			
		||||
    volatile uint8_t *TX_CTRL;          ///< EP transmit control register
 | 
			
		||||
    volatile uint8_t *RX_CTRL;          ///< EP receive control register
 | 
			
		||||
} USB_EP_Ctrl;
 | 
			
		||||
 | 
			
		||||
// clang-format off
 | 
			
		||||
static const USB_EP_Ctrl USB_EPCtrl[USB_NUM_OF_ENDPOINTS] = {
 | 
			
		||||
    {NULL,                0,                0,                0,                  &(USBG->UEP0_DMA), &(USBG->UEP0_TX_LEN), &(USBG->UEP0_TX_CTRL), &(USBG->UEP0_RX_CTRL)}, // EP0
 | 
			
		||||
    {&(USBG->UEP4_1_MOD), USBFS_UEP1_RX_EN, USBFS_UEP1_TX_EN, USBFS_UEP1_BUF_MOD, &(USBG->UEP1_DMA), &(USBG->UEP1_TX_LEN), &(USBG->UEP1_TX_CTRL), &(USBG->UEP1_RX_CTRL) }, // EP1
 | 
			
		||||
    {&(USBG->UEP2_3_MOD), USBFS_UEP2_RX_EN, USBFS_UEP2_TX_EN, USBFS_UEP2_BUF_MOD, &(USBG->UEP2_DMA), &(USBG->UEP2_TX_LEN), &(USBG->UEP2_TX_CTRL), &(USBG->UEP2_RX_CTRL) }, // EP2
 | 
			
		||||
    {&(USBG->UEP2_3_MOD), USBFS_UEP3_RX_EN, USBFS_UEP3_TX_EN, USBFS_UEP3_BUF_MOD, &(USBG->UEP3_DMA), &(USBG->UEP3_TX_LEN), &(USBG->UEP3_TX_CTRL), &(USBG->UEP3_RX_CTRL) }, // EP3
 | 
			
		||||
    {&(USBG->UEP4_1_MOD), USBFS_UEP4_RX_EN, USBFS_UEP4_TX_EN, USBFS_UEP4_BUF_MOD, &(USBG->UEP4_DMA), &(USBG->UEP4_TX_LEN), &(USBG->UEP4_TX_CTRL), &(USBG->UEP4_RX_CTRL) }, // EP4
 | 
			
		||||
    {&(USBG->UEP5_6_MOD), USBFS_UEP5_RX_EN, USBFS_UEP5_TX_EN, USBFS_UEP5_BUF_MOD, &(USBG->UEP5_DMA), &(USBG->UEP5_TX_LEN), &(USBG->UEP5_TX_CTRL), &(USBG->UEP5_RX_CTRL) }, // EP5
 | 
			
		||||
    {&(USBG->UEP5_6_MOD), USBFS_UEP6_RX_EN, USBFS_UEP6_TX_EN, USBFS_UEP6_BUF_MOD, &(USBG->UEP6_DMA), &(USBG->UEP6_TX_LEN), &(USBG->UEP6_TX_CTRL), &(USBG->UEP6_RX_CTRL) }, // EP6
 | 
			
		||||
    {&(USBG->UEP7_MOD),   USBFS_UEP7_RX_EN, USBFS_UEP7_TX_EN, USBFS_UEP7_BUF_MOD, &(USBG->UEP7_DMA), &(USBG->UEP7_TX_LEN), &(USBG->UEP7_TX_CTRL), &(USBG->UEP7_RX_CTRL) }, // EP7
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// clang-format on
 | 
			
		||||
 | 
			
		||||
// configure USB endpoint
 | 
			
		||||
void usbdrv_configure_endpoint(uint8_t ep, uint8_t dir, const USBDRV_EpConfig *cfg) {
 | 
			
		||||
    const USB_EP_Ctrl *epc = USB_EPCtrl + ep; // get Endpoint control
 | 
			
		||||
 | 
			
		||||
    if (dir == USB_OUT) { // ---- OUT ----
 | 
			
		||||
 | 
			
		||||
        if (ep != 0) {                              // SPECIAL treatment to EP0, that one cannot be turned on or off
 | 
			
		||||
            CLEAR_BIT(*epc->UEP_MOD, epc->BUF_MOD); // clear BUFMOD bit
 | 
			
		||||
            SET_BIT(*epc->UEP_MOD, epc->RX_EN);     // set RX enable bit
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SET_BIT(*epc->RX_CTRL, USBFS_UEP_R_AUTO_TOG); // turn on automatic sync bit toggling
 | 
			
		||||
 | 
			
		||||
        // ---- common for all endpoints ----
 | 
			
		||||
 | 
			
		||||
        // NAK processing
 | 
			
		||||
        CLEAR_BIT(*epc->RX_CTRL, USBFS_UEP_R_RES_MASK);
 | 
			
		||||
        if (cfg->responding_NAK) {
 | 
			
		||||
            SET_BIT(*epc->RX_CTRL, USBFS_UEP_R_RES_NAK); // send NAK
 | 
			
		||||
        } else {
 | 
			
		||||
            usbdrv_arm_OUT_endpoint(ep, cfg->max_packet_size);
 | 
			
		||||
        }
 | 
			
		||||
    } else { // ---- IN ----
 | 
			
		||||
 | 
			
		||||
        if (ep != 0) {                                    // SPECIAL treatment to EP0, that one cannot be turned on or off
 | 
			
		||||
            CLEAR_BIT(*epc->UEP_MOD, epc->BUF_MOD);       // clear BUFMOD bit
 | 
			
		||||
            SET_BIT(*epc->UEP_MOD, epc->TX_EN);           // set TX enable bit
 | 
			
		||||
            SET_BIT(*epc->TX_CTRL, USBFS_UEP_T_AUTO_TOG); // turn on automatic sync bit toggling
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // ---- common for all endpoints ----
 | 
			
		||||
 | 
			
		||||
        // NAK processing
 | 
			
		||||
        CLEAR_BIT(*epc->TX_CTRL, USBFS_UEP_T_RES_MASK);
 | 
			
		||||
        // if (cfg->responding_NAK) {
 | 
			
		||||
        SET_BIT(*epc->TX_CTRL, USBFS_UEP_T_RES_NAK); // send NAK by default
 | 
			
		||||
        //}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// deconfigure USB endpoint
 | 
			
		||||
void usbdrv_deconfigure_endpoint(uint8_t ep, uint8_t dir) {
 | 
			
		||||
    if (ep == 0) { // EP0 cannot be deconfigured
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const USB_EP_Ctrl *epc = USB_EPCtrl + ep; // get Endpoint control
 | 
			
		||||
 | 
			
		||||
    if (dir == USB_OUT) {                       // ---- OUT ----
 | 
			
		||||
        CLEAR_BIT(*epc->UEP_MOD, epc->BUF_MOD); // clear BUFMOD bit
 | 
			
		||||
        CLEAR_BIT(*epc->UEP_MOD, epc->RX_EN);   // clear RX enable bit
 | 
			
		||||
    } else {                                    // ---- IN ----
 | 
			
		||||
        CLEAR_BIT(*epc->UEP_MOD, epc->BUF_MOD); // clear BUFMOD bit
 | 
			
		||||
        CLEAR_BIT(*epc->UEP_MOD, epc->TX_EN);   // clear TX enable bit
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ---------------------
 | 
			
		||||
 | 
			
		||||
// stall endpoint
 | 
			
		||||
void usbdrv_stall_endpoint(uint8_t ep, uint8_t dir, bool stall) {
 | 
			
		||||
    const USB_EP_Ctrl *epc = USB_EPCtrl + ep;
 | 
			
		||||
 | 
			
		||||
    if (dir == USB_IN) {
 | 
			
		||||
        CLEAR_BIT(*epc->RX_CTRL, USBFS_UEP_R_RES_MASK);
 | 
			
		||||
        if (stall) {
 | 
			
		||||
            SET_BIT(*epc->RX_CTRL, USBFS_UEP_R_RES_STALL); // stall endpoint
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        CLEAR_BIT(*epc->RX_CTRL, USBFS_UEP_T_RES_MASK);
 | 
			
		||||
        if (stall) {
 | 
			
		||||
            SET_BIT(*epc->TX_CTRL, USBFS_UEP_T_RES_STALL); // stall endpoint
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------
 | 
			
		||||
 | 
			
		||||
// write data to specific endpoint FIFO
 | 
			
		||||
uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len) {
 | 
			
		||||
    // proceed only if it was not armed before
 | 
			
		||||
    if (gs.ep_IN[ep].txp) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // get Endpoint control data
 | 
			
		||||
    const USB_EP_Ctrl *epc = USB_EPCtrl + ep;
 | 
			
		||||
 | 
			
		||||
    // constrain copy length
 | 
			
		||||
    uint16_t txLen = MIN(len, USB_EP_TX_BUF_SIZE);
 | 
			
		||||
 | 
			
		||||
    // copy data to the output buffer
 | 
			
		||||
    if (txLen > 0) {
 | 
			
		||||
        uint8_t *txBuf = USB_EP_GET_EP0_BUFFER();
 | 
			
		||||
        memcpy(txBuf, data, txLen);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // set transmission length
 | 
			
		||||
    *epc->TRANSMIT_LENGTH = txLen;
 | 
			
		||||
 | 
			
		||||
    // append ZLP only, if packet size is MAX_PCKT_SIZE (this way to ZLP is injected in a longer packet whose first part is limited to 64 bytes)
 | 
			
		||||
    gs.ep_IN[ep].zlp_next = (len == USB_MAX_FS_PCKT_SIZE_NON_ISOCHRONOUS);
 | 
			
		||||
 | 
			
		||||
    // EP0 must begin responding with DATA1
 | 
			
		||||
    // if (ep == 0) {
 | 
			
		||||
    //     SET_BIT(*epc->TX_CTRL, USBFS_UEP_T_TOG);
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    // signal that transmission is in progress
 | 
			
		||||
    gs.ep_IN[ep].txp = true;
 | 
			
		||||
 | 
			
		||||
    // enable transmission
 | 
			
		||||
    CLEAR_BIT(*epc->TX_CTRL, USBFS_UEP_T_RES_MASK);
 | 
			
		||||
 | 
			
		||||
    // return with written size
 | 
			
		||||
    return txLen;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// arm OUT endpoint
 | 
			
		||||
uint32_t usbdrv_arm_OUT_endpoint(uint8_t ep, uint16_t size) {
 | 
			
		||||
    // proceed only if it was not armed before
 | 
			
		||||
    if (gs.ep_OUT[ep].txp) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // cap size at max packet size defined for this endpoint
 | 
			
		||||
    size = MIN(gs.ep_OUT[ep].max_packet_size, size);
 | 
			
		||||
 | 
			
		||||
    // get Endpoint control data
 | 
			
		||||
    const USB_EP_Ctrl *epc = USB_EPCtrl + ep;
 | 
			
		||||
 | 
			
		||||
    // copy data to the output buffer
 | 
			
		||||
    // uint32_t *rxBuf = (uint32_t *)(((uint32_t)(*epc->BUF_START_ADDR)) + USB_EP_TX_BUF_SIZE);
 | 
			
		||||
 | 
			
		||||
    // enable transmission
 | 
			
		||||
    CLEAR_BIT(*epc->RX_CTRL, USBFS_UEP_R_RES_MASK);
 | 
			
		||||
 | 
			
		||||
    // signal that transmission is in progress
 | 
			
		||||
    gs.ep_OUT[ep].txp = true;
 | 
			
		||||
 | 
			
		||||
    // return with armed size
 | 
			
		||||
    return size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void usbdrv_autoarm_OUT_endpoint(uint8_t ep) {
 | 
			
		||||
    gs.ep_OUT[ep].autoarm = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------
 | 
			
		||||
 | 
			
		||||
void usbdrv_enable_endpoint_interrupt(uint8_t ep, uint8_t dir, bool en) {
 | 
			
		||||
    return; // FIXME
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// preload usb endpoint config
 | 
			
		||||
void usbdrv_preload_endpoint_config(uint8_t ep, uint8_t dir, const USBDRV_EpConfig *cfg) {
 | 
			
		||||
    USBMSG("PRELOAD: %u %s\n", ep, dir ? "IN" : "OUT");
 | 
			
		||||
    if (dir == USB_OUT) {
 | 
			
		||||
        gs.ep_OUT[ep] = *cfg;
 | 
			
		||||
        gs.ep_OUT[ep].is_configured = true;
 | 
			
		||||
    } else {
 | 
			
		||||
        gs.ep_IN[ep] = *cfg;
 | 
			
		||||
        gs.ep_IN[ep].is_configured = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// clear endpoint config
 | 
			
		||||
void usbdrv_clear_endpoint_config() {
 | 
			
		||||
    memset(&gs.ep_OUT, 0, USB_NUM_OF_ENDPOINTS * sizeof(USBDRV_EpConfig));
 | 
			
		||||
    memset(&gs.ep_IN, 0, USB_NUM_OF_ENDPOINTS * sizeof(USBDRV_EpConfig));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// apply preloaded endpoint configuration
 | 
			
		||||
void usbdrv_apply_endpoint_config() {
 | 
			
		||||
    for (uint8_t i = 0; i < USB_NUM_OF_ENDPOINTS; i++) {
 | 
			
		||||
        // OUT EPs
 | 
			
		||||
        if (gs.ep_OUT[i].is_configured) {
 | 
			
		||||
            usbdrv_configure_endpoint(i, USB_OUT, gs.ep_OUT + i);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // IN EPs
 | 
			
		||||
        if (gs.ep_IN[i].is_configured) {
 | 
			
		||||
            usbdrv_configure_endpoint(i, USB_IN, gs.ep_IN + i);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// fetch endpoint configuration from descriptor dump
 | 
			
		||||
void usbdrv_fetch_endpoint_configuration(uint8_t config_index) {
 | 
			
		||||
    const uint8_t *fullConfDesc = (const uint8_t *)confDescs[config_index];                         // point an array to the beginning of the full configuration
 | 
			
		||||
    const USB_ConfigurationDesc *confDesc = (const USB_ConfigurationDesc *)confDescs[config_index]; // fetch the leading configuration descriptor
 | 
			
		||||
 | 
			
		||||
    // look up endpoint descriptors
 | 
			
		||||
    const uint8_t *iter = fullConfDesc;
 | 
			
		||||
    while (iter < (fullConfDesc + confDesc->wTotalLength)) {
 | 
			
		||||
        if (iter[1] == UD_Endpoint) { // Endpoint descriptor found
 | 
			
		||||
            USB_EndpointDesc epDesc;
 | 
			
		||||
            memcpy(&epDesc, iter, iter[0]); // fetch EP descriptor by copy, since desciptor start address is NOT aligned
 | 
			
		||||
            USBDRV_EpConfig cfg;            // fill-in configuration
 | 
			
		||||
            cfg.max_packet_size = epDesc.wMaxPacketSize;
 | 
			
		||||
            cfg.responding_NAK = false;
 | 
			
		||||
            cfg.type = epDesc.bmAttributes & 0b11;
 | 
			
		||||
            cfg.service_interval = epDesc.bInterval;
 | 
			
		||||
 | 
			
		||||
            // fetch endpoint address
 | 
			
		||||
            uint8_t dir = (epDesc.bEndpointAddress >> 7);
 | 
			
		||||
            uint8_t n = epDesc.bEndpointAddress & 0x7F;
 | 
			
		||||
 | 
			
		||||
            // apply configuration
 | 
			
		||||
            usbdrv_preload_endpoint_config(n, dir, &cfg);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // advance iterator using the bLength field (first byte in a descriptor)
 | 
			
		||||
        iter += iter[0];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    usbdrv_allocate_buffers();
 | 
			
		||||
 | 
			
		||||
    usbdrv_apply_endpoint_config();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// #define USBDRV_ADDR_TABLE_STR_LEN (255)
 | 
			
		||||
// static char usbdrv_addr_table[USBDRV_ADDR_TABLE_STR_LEN + 1];
 | 
			
		||||
 | 
			
		||||
// build buffer structure, allocate buffers (compute addresses)
 | 
			
		||||
void usbdrv_allocate_buffers() {
 | 
			
		||||
    for (uint8_t i = 0; i < USB_NUM_OF_ENDPOINTS; i++) {
 | 
			
		||||
        *USB_EPCtrl[i].BUF_START_ADDR = (uint32_t)USB_EP_GET_TX_BUFFER(i);
 | 
			
		||||
 | 
			
		||||
        USBDRV_EpConfig *cfg = &gs.ep_IN[i];
 | 
			
		||||
        if (cfg->is_configured) {
 | 
			
		||||
            cfg->buffer_address = (uint32_t)(*USB_EPCtrl[i].BUF_START_ADDR); // store DMA start address
 | 
			
		||||
            cfg->zlp_next = false;
 | 
			
		||||
            cfg->txp = false; // no transfer is in progress
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ---------------------
 | 
			
		||||
 | 
			
		||||
// create an initial setup for EP0 in both directions
 | 
			
		||||
void usbdrv_initial_ep0_setup() {
 | 
			
		||||
    // setup EP0 OUT and IN
 | 
			
		||||
    USBDRV_EpConfig ep_cfg;
 | 
			
		||||
    ep_cfg.max_packet_size = 64;
 | 
			
		||||
    ep_cfg.responding_NAK = false;
 | 
			
		||||
    usbdrv_preload_endpoint_config(0, USB_OUT, &ep_cfg);
 | 
			
		||||
    usbdrv_preload_endpoint_config(0, USB_IN, &ep_cfg);
 | 
			
		||||
 | 
			
		||||
    // build FIFO
 | 
			
		||||
    usbdrv_allocate_buffers();
 | 
			
		||||
 | 
			
		||||
    // configure endpoints
 | 
			
		||||
    usbdrv_apply_endpoint_config();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ---------------------
 | 
			
		||||
 | 
			
		||||
void usbdrv_set_address(uint8_t addr) {
 | 
			
		||||
    gs.address = addr;
 | 
			
		||||
    gs.address_pending = true; // cannot set address immediately, have to wait for next IN transaction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ---------------------
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Function prototype for processing SETUP packets. This function is expected to be
 | 
			
		||||
 * overridden by the application.
 | 
			
		||||
 *
 | 
			
		||||
 * @param data pointer to the SETUP packet
 | 
			
		||||
 * @param size size of the packet
 | 
			
		||||
 * @param stage stage of the SETUP transaction
 | 
			
		||||
 */
 | 
			
		||||
__weak void usbcore_process_setup_pckt(const uint8_t *data, uint16_t size, uint8_t stage) {
 | 
			
		||||
    // always pass ALIGNED data!
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Function prototype for processing non-SETUP packets. This function is expected to be
 | 
			
		||||
 * overridden by the application.
 | 
			
		||||
 *
 | 
			
		||||
 * @param cbcpd pointer to callback compound
 | 
			
		||||
 */
 | 
			
		||||
__weak void usbcore_process_nonsetup_event(UsbDrv_CallbackCompound *cbcpd) {
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define USB_INT_STATUS_GET_EP(s) ((s) & USBFS_UIS_ENDP_MASK)     ///< Get EP number from interrupt status
 | 
			
		||||
#define USB_INT_STATUS_GET_TOKEN(s) ((s) & USBFS_UIS_TOKEN_MASK) ///< Get token of the interrupt  (no shifting!)
 | 
			
		||||
#define USB_INT_STATUS_IS_NAK(s) (((s) & USBFS_UIS_IS_NAK) != 0) ///< Was it a NAK transmission?
 | 
			
		||||
 | 
			
		||||
// TODO: egy input buffer kellene ide, mert különben egy lassú feldolgozás felborít mindent!
 | 
			
		||||
 | 
			
		||||
// process USB event
 | 
			
		||||
void usbdrv_process_event(uint8_t evt_code, USBDRV_EventData *evt_data) {
 | 
			
		||||
    if (evt_code == USB_EVT_USB_RESET) { // reset takes precedence over anything else TODO
 | 
			
		||||
        usbdrv_reset();
 | 
			
		||||
 | 
			
		||||
        // invoke Reset Done notification
 | 
			
		||||
        if (drvIntf.rst_notify != NULL) {
 | 
			
		||||
            drvIntf.rst_notify();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        USBMSG("RESET\n");
 | 
			
		||||
        return;
 | 
			
		||||
    } else if (evt_code == USB_EVT_TRANSFER_COMPLETION) { // transfer complete
 | 
			
		||||
        uint8_t status = USBG->INT_ST;                    // read interrupt status register
 | 
			
		||||
        uint8_t token = USB_INT_STATUS_GET_TOKEN(status);
 | 
			
		||||
        uint8_t ep = USB_INT_STATUS_GET_EP(status);
 | 
			
		||||
        bool nak = USB_INT_STATUS_IS_NAK(status);
 | 
			
		||||
        uint16_t len = USBG->RX_LEN;
 | 
			
		||||
 | 
			
		||||
        UsbDrv_CallbackCompound cbcpd;
 | 
			
		||||
        cbcpd.ep = ep;
 | 
			
		||||
 | 
			
		||||
        switch (token) {
 | 
			
		||||
        case USBFS_UIS_TOKEN_OUT: {
 | 
			
		||||
            if (ep == 0) {
 | 
			
		||||
                uint8_t *rxBuf = USB_EP_GET_EP0_BUFFER();
 | 
			
		||||
                usbcore_process_setup_pckt(rxBuf, len, UST_DATA);
 | 
			
		||||
            } else {
 | 
			
		||||
                cbcpd.dir = USB_OUT;
 | 
			
		||||
                cbcpd.code = USB_CBC_OUT;
 | 
			
		||||
                cbcpd.data = USB_EP_GET_RX_BUFFER(ep);
 | 
			
		||||
                cbcpd.size = len;
 | 
			
		||||
                usbcore_process_nonsetup_event(&cbcpd);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (ep != 0) {
 | 
			
		||||
                SET_BIT(*USB_EPCtrl[ep].RX_CTRL, USBFS_UEP_R_RES_NAK); // send NAK
 | 
			
		||||
                gs.ep_OUT[ep].txp = false;                             // transfer concluded
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ((ep == 0) || (gs.ep_OUT[ep].autoarm)) {                     // EP0 must always be armed
 | 
			
		||||
                usbdrv_arm_OUT_endpoint(ep, gs.ep_OUT[ep].max_packet_size); // arm endpoint
 | 
			
		||||
                gs.ep_OUT[ep].autoarm = false;                              // clear autoarm flag
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        } break;
 | 
			
		||||
        case USBFS_UIS_TOKEN_IN: {
 | 
			
		||||
            if (gs.ep_IN[ep].zlp_next) {
 | 
			
		||||
                usbdrv_arm_IN_endpoint(ep, NULL, 0); // send ZLP
 | 
			
		||||
            } else {                                 // no ZLP
 | 
			
		||||
                cbcpd.dir = USB_IN;
 | 
			
		||||
                cbcpd.code = USB_CBC_IN_DONE;
 | 
			
		||||
                cbcpd.data = NULL;
 | 
			
		||||
                cbcpd.size = 0;
 | 
			
		||||
 | 
			
		||||
                SET_BIT(*USB_EPCtrl[ep].TX_CTRL, USBFS_UEP_T_RES_NAK); // send NAK
 | 
			
		||||
                *USB_EPCtrl[ep].TRANSMIT_LENGTH = 0;                   // zero transmit length
 | 
			
		||||
 | 
			
		||||
                // usbcore_process_nonsetup_event(&cbcpd);
 | 
			
		||||
 | 
			
		||||
                // change address
 | 
			
		||||
                if (gs.address_pending) {
 | 
			
		||||
                    USBG->DEV_ADDR = gs.address;
 | 
			
		||||
                    gs.address_pending = false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                gs.ep_IN[ep].txp = false; // transfer concluded
 | 
			
		||||
 | 
			
		||||
                // toggle EP0 synchronization bit
 | 
			
		||||
                if (ep == 0) {
 | 
			
		||||
                    bool tog = !GET_BIT(*USB_EPCtrl[0].TX_CTRL, USBFS_UEP_T_TOG);
 | 
			
		||||
                    if (tog) { // DATA1 is the next transfer
 | 
			
		||||
                        SET_BIT(*USB_EPCtrl[0].TX_CTRL, USBFS_UEP_T_TOG);
 | 
			
		||||
                    } else { // DATA0 is the next transfer
 | 
			
		||||
                        CLEAR_BIT(*USB_EPCtrl[0].TX_CTRL, USBFS_UEP_T_TOG);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (nak) {
 | 
			
		||||
                    __NOP();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // invoke callback if registered
 | 
			
		||||
                if (cbs[ep] != NULL) {
 | 
			
		||||
                    UsbDrv_IN_cb cb = cbs[ep]; // fetch function pointer
 | 
			
		||||
                    cbs[ep] = NULL;            // clear callback
 | 
			
		||||
                    cb(ep);                    // invoke the callback
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } break;
 | 
			
		||||
        case USBFS_UIS_TOKEN_SETUP: {
 | 
			
		||||
            SET_BIT(*USB_EPCtrl[0].TX_CTRL, USBFS_UEP_T_TOG); // secure starting with DATA1 if an IN follows
 | 
			
		||||
            uint8_t *rxBuf = USB_EP_GET_EP0_BUFFER();         // the receive buffer
 | 
			
		||||
            usbcore_process_setup_pckt(rxBuf, 8, UST_SETUP);  // process the setup packet
 | 
			
		||||
        } break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ---------------------
 | 
			
		||||
 | 
			
		||||
#define PROCESS_EVENT(evt, data) usbdrv_process_event((evt), (data))
 | 
			
		||||
 | 
			
		||||
void USB_IRQ_HANDLER() {
 | 
			
		||||
 | 
			
		||||
    uint32_t ints = USBG->INT_FG;
 | 
			
		||||
 | 
			
		||||
    // USB reset
 | 
			
		||||
    if (ints & USBFS_UIF_BUS_RST) {
 | 
			
		||||
        SET_BIT(USBG->INT_FG, USBFS_UIF_BUS_RST); // clear interrupt
 | 
			
		||||
        // PROCESS_EVENT(USB_EVT_USB_RESET, NULL);         // process event
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // USB Suspend
 | 
			
		||||
    if (ints & USBFS_UIF_SUSPEND) {
 | 
			
		||||
        SET_BIT(USBG->INT_FG, USBFS_UIF_SUSPEND); // clear interrupt
 | 
			
		||||
        USBMSG("SUSPEND\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // FIFO overflow
 | 
			
		||||
    if (ints & USBFS_UIF_FIFO_OV) {
 | 
			
		||||
        SET_BIT(USBG->INT_FG, USBFS_UIF_FIFO_OV); // clear interrupt
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Transfer complete
 | 
			
		||||
    if (ints & USBFS_UIF_TRANSFER) {
 | 
			
		||||
        PROCESS_EVENT(USB_EVT_TRANSFER_COMPLETION, NULL); // process event
 | 
			
		||||
        SET_BIT(USBG->INT_FG, USBFS_UIF_TRANSFER);        // clear interrupt
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										241
									
								
								driver/ch32/usb_drv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								driver/ch32/usb_drv.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,241 @@
 | 
			
		||||
#ifndef CH32_USB_DRV
 | 
			
		||||
#define CH32_USB_DRV
 | 
			
		||||
 | 
			
		||||
#include "../../usb_common_types.h"
 | 
			
		||||
 | 
			
		||||
#include "../../usb_driver_common.h"
 | 
			
		||||
 | 
			
		||||
// number of supported endpoints
 | 
			
		||||
#define USB_NUM_OF_ENDPOINTS (8) // set it to the maximum that this type of module can support
 | 
			
		||||
 | 
			
		||||
// non isochronous transfers
 | 
			
		||||
#define USB_MAX_FS_PCKT_SIZE_NON_ISOCHRONOUS (64)
 | 
			
		||||
 | 
			
		||||
// isochronous transfers
 | 
			
		||||
#define USB_MAX_FS_PCKT_SIZE_ISOCHRONOUS (1023)
 | 
			
		||||
 | 
			
		||||
// endpoint configuration structure
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint16_t max_packet_size; // maximum packet size
 | 
			
		||||
    bool8_t responding_NAK;   // indicates if endpoint responds with NAK
 | 
			
		||||
    uint8_t type;             // endpoint type
 | 
			
		||||
    uint8_t service_interval; // service interval
 | 
			
		||||
 | 
			
		||||
    // calculated values
 | 
			
		||||
 | 
			
		||||
    uint8_t is_configured;   // the endpoint is in use
 | 
			
		||||
    uint16_t buffer_address; // address in the FIFO
 | 
			
		||||
    bool8_t zlp_next;        // indicates, that ZLP should be transmitted at the end of the current transfer (for IN endpoints)
 | 
			
		||||
    bool8_t autoarm;         // automatically arm endpoint (for OUT endpoints)
 | 
			
		||||
    bool8_t txp;             // transfer in progress
 | 
			
		||||
} USBDRV_EpConfig;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    USB_EVT_USB_RESET, // bus reset received
 | 
			
		||||
    USB_EVT_TRANSFER_COMPLETION,
 | 
			
		||||
} USBDRV_EventCode;
 | 
			
		||||
 | 
			
		||||
// USB device state
 | 
			
		||||
typedef struct {
 | 
			
		||||
    USBDRV_EpConfig ep_OUT[USB_NUM_OF_ENDPOINTS]; // OUT endpoint configs
 | 
			
		||||
    USBDRV_EpConfig ep_IN[USB_NUM_OF_ENDPOINTS];  // IN endpoint configs
 | 
			
		||||
    uint8_t *buf;                                 // pointer to the receive buffer (this way declaration can be separated)
 | 
			
		||||
    uint8_t address;                              // device address
 | 
			
		||||
    bool address_pending;                         // address change is pending
 | 
			
		||||
} USBDRV_GlobalState;
 | 
			
		||||
 | 
			
		||||
// event data
 | 
			
		||||
typedef union {
 | 
			
		||||
    struct {
 | 
			
		||||
        uint8_t pckt_status; // read packet status
 | 
			
		||||
        uint8_t data_pid;    // data PID
 | 
			
		||||
        uint8_t byte_count;  // byte count
 | 
			
		||||
        uint8_t ep_num;      // read endpoint number
 | 
			
		||||
    } rx;                    // receive event data
 | 
			
		||||
} USBDRV_EventData;
 | 
			
		||||
 | 
			
		||||
// event compound for queueing
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t code;         // event code
 | 
			
		||||
    USBDRV_EventData data; // accompaining event data
 | 
			
		||||
} USBDRV_EventCompound;
 | 
			
		||||
 | 
			
		||||
// ------------
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Fully initialize USB driver.
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_init();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Reset USB driver.
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_reset();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Init driver's global state.
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_init_global_state();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Initialize driver interface.
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_init_intf();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * USB peripheral initialization.
 | 
			
		||||
 *
 | 
			
		||||
 * @param reset only perform an after-reset reinitialization
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_periph_init(bool reset);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Clear all TX and RX FIFOs.
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_clear_all_fifos();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Power down or up the USB peripheral. Also control built-in transciever.
 | 
			
		||||
 *
 | 
			
		||||
 * @param en power on/off
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_power_and_connect(bool en);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Configure USB Endpoint.
 | 
			
		||||
 *
 | 
			
		||||
 * @param ep index of the endpoint
 | 
			
		||||
 * @param dir direction of the endpoint to be configured
 | 
			
		||||
 * @param cfg pointer to the configuration details
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_configure_endpoint(uint8_t ep, uint8_t dir, const USBDRV_EpConfig *cfg);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Deconfigure a specific USB Endpoint.
 | 
			
		||||
 *
 | 
			
		||||
 * @param ep index of the endpoint
 | 
			
		||||
 * @param dir direction of the endpoint to be deconfigured
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_deconfigure_endpoint(uint8_t ep, uint8_t dir);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Stall a particular USB Endpoint.
 | 
			
		||||
 *
 | 
			
		||||
 * @param ep index of the endpoint to be stalled
 | 
			
		||||
 * @param dir direction of the endpoint
 | 
			
		||||
 * @param stall enable/disable stalling
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_stall_endpoint(uint8_t ep, uint8_t dir, bool stall);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Setup and prepare Endpoint to transfer data towards the host.
 | 
			
		||||
 * May be called multiple times in a single transmission, since
 | 
			
		||||
 * large messages do not have to fit into a single buffer.
 | 
			
		||||
 *
 | 
			
		||||
 * @param ep index of the Endpoint
 | 
			
		||||
 * @param data pointer to the data
 | 
			
		||||
 * @param len length of the data to be read
 | 
			
		||||
 * @return number of bytes read from the data buffer
 | 
			
		||||
 */
 | 
			
		||||
uint32_t usbdrv_arm_IN_endpoint(uint8_t ep, const uint8_t *data, uint16_t len);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Prepare Endpoint to expect data reception from the host.
 | 
			
		||||
 *
 | 
			
		||||
 * @param ep index of the Endpoint
 | 
			
		||||
 * @param size expected reception length
 | 
			
		||||
 * @return message length that the endpoint can support during next reception
 | 
			
		||||
 */
 | 
			
		||||
uint32_t usbdrv_arm_OUT_endpoint(uint8_t ep, uint16_t size);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Enable or disable OUT Endpoint auto arming.
 | 
			
		||||
 * Right after a transaction completes the USB core
 | 
			
		||||
 * automatically prepares the endpoint for the next
 | 
			
		||||
 * reception if this feature is enabled.
 | 
			
		||||
 *
 | 
			
		||||
 * @param ep index of the Endpoint
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_autoarm_OUT_endpoint(uint8_t ep);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Mask or unmask Endpoint interrupt generation.
 | 
			
		||||
 *
 | 
			
		||||
 * @param ep index of the Endpoint
 | 
			
		||||
 * @param dir direction of the Endpoint
 | 
			
		||||
 * @param en enable/disable interrupt
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_enable_endpoint_interrupt(uint8_t ep, uint8_t dir, bool en);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Preload Endpoint config. Do not write configuration
 | 
			
		||||
 * to the hardware right away, just buffer them in.
 | 
			
		||||
 *
 | 
			
		||||
 * @param ep index of the Endpoint
 | 
			
		||||
 * @param dir direction of the Endpint
 | 
			
		||||
 * @param cfg pointer to Endpoint configuration
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_preload_endpoint_config(uint8_t ep, uint8_t dir, const USBDRV_EpConfig *cfg);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Clear ALL Endpoints' preload configurations.
 | 
			
		||||
 * Does NOT clear configuration in the hardware!
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_clear_endpoint_config();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Apply preloaded Endpoint configuration, write
 | 
			
		||||
 * Endpoint config to the hardware.
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_apply_endpoint_config();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Select a specific configuration from the descriptor
 | 
			
		||||
 * dump, preload Endpoint settings and finally apply them.
 | 
			
		||||
 *
 | 
			
		||||
 * @param config_index configuration index
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_fetch_endpoint_configuration(uint8_t config_index);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Construct FIFO considering configured Endpoints.
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_allocate_buffers();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Apply an initial EP0 setup.
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_initial_ep0_setup();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Set USB device address.
 | 
			
		||||
 *
 | 
			
		||||
 * @param addr device address
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_set_address(uint8_t addr);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get driver interface.
 | 
			
		||||
 *
 | 
			
		||||
 * @return pointer to the driver interface
 | 
			
		||||
 */
 | 
			
		||||
UsbDrv_DrvIntf *usbdrv_get_intf();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Register callback for IN transaction complete.
 | 
			
		||||
 *
 | 
			
		||||
 * @param ep index of the Endpoint
 | 
			
		||||
 * @param cb pointer to the callback function
 | 
			
		||||
 */
 | 
			
		||||
void usbdrv_register_IN_complete_cb(uint8_t ep, UsbDrv_IN_cb cb);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get Endpoint interrupt flag.
 | 
			
		||||
 *
 | 
			
		||||
 * @param ep index of the Endpoint
 | 
			
		||||
 * @param dir direction of the Endpoint
 | 
			
		||||
 * @return flag was set
 | 
			
		||||
 */
 | 
			
		||||
bool usbdrv_get_endpoint_interrupt_flag(uint8_t ep, uint8_t dir);
 | 
			
		||||
 | 
			
		||||
#endif /* CH32_USB_DRV */
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user