Compare commits
	
		
			No commits in common. "master" and "core_fix_2" have entirely different histories.
		
	
	
		
			master
			...
			core_fix_2
		
	
		
							
								
								
									
										88
									
								
								class/acm.c
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								class/acm.c
									
									
									
									
									
								
							@ -9,15 +9,12 @@
 | 
			
		||||
#include "acm.h"
 | 
			
		||||
 | 
			
		||||
#include <memory.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "../usb.h"
 | 
			
		||||
#include "../usb_device_types.h"
 | 
			
		||||
#include "cmsis_os2.h"
 | 
			
		||||
 | 
			
		||||
#include <blocking_io/blocking_fifo.h>
 | 
			
		||||
#include <strings.h>
 | 
			
		||||
 | 
			
		||||
// -------------------------
 | 
			
		||||
 | 
			
		||||
@ -25,43 +22,6 @@ static Usb_AcmState acms = {0};                 ///< ACM module state
 | 
			
		||||
static uint8_t tx_buffer[USB_ACM_PCKT_BUFSIZE]; ///< Transmit buffer
 | 
			
		||||
static uint8_t fifo_mem[USB_ACM_FIFO_MEM_SIZE]; ///< Memory assigned to the TX BFifo
 | 
			
		||||
static BFifo fifo;                              ///< TX Blocking FIFO
 | 
			
		||||
static osThreadId_t th;                         ///< ACM thread
 | 
			
		||||
static osEventFlagsId_t flags;                  ///< Event flags
 | 
			
		||||
 | 
			
		||||
#define USB_ACM_DATA_IN_DONE (0x01)         ///< IN transfer done flag
 | 
			
		||||
#define USB_ACM_COMM_INIT (0x02)            ///< Communication has been initialized
 | 
			
		||||
#define USB_ACM_HOSTBOUND_DATA_AVAIL (0x04) ///< Hostbound data is available
 | 
			
		||||
 | 
			
		||||
// -------------------------
 | 
			
		||||
 | 
			
		||||
static void thread_usb_acm(void *arg) {
 | 
			
		||||
    osEventFlagsWait(flags, USB_ACM_COMM_INIT, 0, osWaitForever); // wait for communication to become initialized
 | 
			
		||||
 | 
			
		||||
    osEventFlagsSet(flags, USB_ACM_DATA_IN_DONE); // assume we can write to the data endpoint
 | 
			
		||||
 | 
			
		||||
    osDelay(100); // inject some initial delay
 | 
			
		||||
 | 
			
		||||
    while (true) {
 | 
			
		||||
        uint32_t signals = osEventFlagsWait(flags, USB_ACM_HOSTBOUND_DATA_AVAIL, osFlagsWaitAny, osWaitForever);
 | 
			
		||||
 | 
			
		||||
        if (signals != osErrorTimeout) {                  // check timeout
 | 
			
		||||
            if (signals & USB_ACM_HOSTBOUND_DATA_AVAIL) { // data hostbound available
 | 
			
		||||
                do {
 | 
			
		||||
                    osEventFlagsWait(flags, USB_ACM_DATA_IN_DONE, osFlagsWaitAny, osWaitForever); // wait for the IN DONE flag
 | 
			
		||||
                    uint32_t readSize = bfifo_read(&fifo, tx_buffer, USB_ACM_PCKT_BUFSIZE);       // read from the fifo
 | 
			
		||||
                    if (readSize > 0) {
 | 
			
		||||
                        uint32_t writeSize = usbcore_schedule_transmission(acms.ep_assignments.data_ep, tx_buffer, readSize); // write data acquired from the buffer
 | 
			
		||||
                        bfifo_pop(&fifo, writeSize, 0);                                                                       // pop with no blocking
 | 
			
		||||
                    }
 | 
			
		||||
                } while (bfifo_get_used(&fifo) > 0);
 | 
			
		||||
                osEventFlagsSet(flags, USB_ACM_DATA_IN_DONE);
 | 
			
		||||
            }
 | 
			
		||||
        } else { // timeout
 | 
			
		||||
            // send an all-zero interrupt
 | 
			
		||||
            // usbcore_schedule_transmission(acms.ep_assignments.control_ep, (const uint8_t *)&(acms.interrupt_data), sizeof(uint16_t));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// -------------------------
 | 
			
		||||
 | 
			
		||||
@ -82,22 +42,13 @@ void usb_acm_init(const Usb_Acm_EpAssignments *as) {
 | 
			
		||||
 | 
			
		||||
    // initialize an all-0 interrupt
 | 
			
		||||
    acms.interrupt_data = 0;
 | 
			
		||||
    acms.interrupt_pending = true;
 | 
			
		||||
 | 
			
		||||
    // communication parameters have not been set
 | 
			
		||||
    acms.commInit = false;
 | 
			
		||||
 | 
			
		||||
    // from now on CDC module is considered initialized
 | 
			
		||||
    acms.moduleInit = true;
 | 
			
		||||
 | 
			
		||||
    // create flags
 | 
			
		||||
    flags = osEventFlagsNew(NULL);
 | 
			
		||||
 | 
			
		||||
    // create thread
 | 
			
		||||
    osThreadAttr_t attr;
 | 
			
		||||
    memset(&attr, 0, sizeof(osThreadAttr_t));
 | 
			
		||||
    attr.stack_size = 2048;
 | 
			
		||||
    attr.name = "acm";
 | 
			
		||||
    th = osThreadNew(thread_usb_acm, NULL, &attr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void usb_cdc_review_comm_init() {
 | 
			
		||||
@ -110,11 +61,6 @@ static void usb_cdc_review_comm_init() {
 | 
			
		||||
 | 
			
		||||
    // combine the above criteria
 | 
			
		||||
    acms.commInit = lcOk && clsOk;
 | 
			
		||||
 | 
			
		||||
    // signal the processing thread
 | 
			
		||||
    if (acms.commInit) {
 | 
			
		||||
        osEventFlagsSet(flags, USB_ACM_COMM_INIT);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int usb_acm_process_and_return(Usb_CallbackEvent *cbevt) {
 | 
			
		||||
@ -135,7 +81,6 @@ int usb_acm_process_and_return(Usb_CallbackEvent *cbevt) {
 | 
			
		||||
        case USB_ACM_GET_LINE_CODING:                               // get line coding
 | 
			
		||||
            cbevt->reply_data = (const uint8_t *)&acms.line_coding; // expert move: pass the pointer, no copying
 | 
			
		||||
            cbevt->reply_size = sizeof(Usb_Acm_LineCodingStruct);
 | 
			
		||||
            usb_cdc_review_comm_init(); // review the communcation initialization state
 | 
			
		||||
            ret = 0;
 | 
			
		||||
            break;
 | 
			
		||||
        case USB_ACM_SEND_BREAK: // send break
 | 
			
		||||
@ -163,11 +108,24 @@ int usb_acm_process_and_return(Usb_CallbackEvent *cbevt) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    case USB_CBEVT_IN: {
 | 
			
		||||
        if (cbevt->ep == acms.ep_assignments.data_ep) {
 | 
			
		||||
            osEventFlagsSet(flags, USB_ACM_DATA_IN_DONE);
 | 
			
		||||
        if (cbevt->ep == acms.ep_assignments.control_ep) { // if notification feeding is requested
 | 
			
		||||
            if (acms.interrupt_pending) {
 | 
			
		||||
                usbcore_schedule_transmission(acms.ep_assignments.control_ep, (const uint8_t *)&(acms.interrupt_data), sizeof(uint16_t)); // send ZLP
 | 
			
		||||
                acms.interrupt_pending = false;
 | 
			
		||||
            }
 | 
			
		||||
            ret = 0;
 | 
			
		||||
        } else if (cbevt->ep == acms.ep_assignments.data_ep) { // if data are requested
 | 
			
		||||
            ret = 0;
 | 
			
		||||
 | 
			
		||||
            // read from the fifo
 | 
			
		||||
            if (acms.commInit) {
 | 
			
		||||
                uint32_t readSize = bfifo_read(&fifo, tx_buffer, USB_ACM_PCKT_BUFSIZE);
 | 
			
		||||
                if (readSize > 0) {
 | 
			
		||||
                    uint32_t writeSize = usbcore_schedule_transmission(acms.ep_assignments.data_ep, tx_buffer, readSize); // write data acquired from the buffer
 | 
			
		||||
                    bfifo_pop(&fifo, writeSize, 0);                                                                       // pop with no blocking
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ret = 0;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
@ -179,19 +137,17 @@ int usb_acm_process_and_return(Usb_CallbackEvent *cbevt) {
 | 
			
		||||
 | 
			
		||||
void usb_acm_write(const uint8_t *data, uint32_t size) {
 | 
			
		||||
    if (acms.moduleInit) {
 | 
			
		||||
        uint32_t index = 0;
 | 
			
		||||
        do {
 | 
			
		||||
            index += bfifo_push(&fifo, data + index, size - index);
 | 
			
		||||
            osEventFlagsSet(flags, USB_ACM_HOSTBOUND_DATA_AVAIL);
 | 
			
		||||
        } while ((size - index) > 0);
 | 
			
		||||
        bfifo_push_all(&fifo, data, size);
 | 
			
		||||
        usbcore_wake_up_endpoint(acms.ep_assignments.data_ep, USB_IN);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @fn void usb_acm_read_callback(const uint8_t *data, uint32_t size)
 | 
			
		||||
 * Callback function prototype for data reception. This function is
 | 
			
		||||
 * expected to be overridden by the application.
 | 
			
		||||
 *
 | 
			
		||||
 * 
 | 
			
		||||
 * @param data ingress data
 | 
			
		||||
 * @param size length of the data
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@ -82,6 +82,7 @@ typedef struct {
 | 
			
		||||
    Usb_Acm_LineCodingStruct line_coding;              ///< Line Coding
 | 
			
		||||
    Usb_Acm_ControlLineStateStruct control_line_state; ///< Control Line State
 | 
			
		||||
    uint16_t interrupt_data;                           ///< Data sent though the next transfer on the notification element
 | 
			
		||||
    bool interrupt_pending;                            ///< Interrupt data is valid and should be send in the next cycle
 | 
			
		||||
    bool moduleInit;                                   ///< CDC module is initialized
 | 
			
		||||
    bool commInit;                                     ///< Communication protocol is initialized
 | 
			
		||||
} Usb_AcmState;
 | 
			
		||||
 | 
			
		||||
@ -1,655 +0,0 @@
 | 
			
		||||
#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))     ///< Combined buffer size in a single direction
 | 
			
		||||
#define USB_EP_SUMMED_BUF_SIZE (USB_EP_COMBINED_BUF_SIZE * USB_NUM_OF_ENDPOINTS) ///< 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) + USB_EP_RX_BUF_SIZE)
 | 
			
		||||
#define USB_EP_GET_RX_BUFFER(ep) (gs.buf + ((ep) * USB_EP_COMBINED_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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Hook for initializing modules after the low-level driver has been initialized
 | 
			
		||||
 * but has not been connected to the bus yet.
 | 
			
		||||
 */
 | 
			
		||||
__weak void usbdrv_init_hook() {
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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_init_hook(); // <---
 | 
			
		||||
    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_MAX_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 = (ep == 0) ? USB_EP_GET_EP0_BUFFER() : USB_EP_GET_TX_BUFFER(ep);
 | 
			
		||||
        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);
 | 
			
		||||
 | 
			
		||||
    // non-EP0 must begin responding with DATA0
 | 
			
		||||
    // if (ep != 0) {
 | 
			
		||||
    //     CLEAR_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_RX_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;
 | 
			
		||||
}
 | 
			
		||||
@ -1,251 +0,0 @@
 | 
			
		||||
#ifndef CH32_USB_DRV
 | 
			
		||||
#define CH32_USB_DRV
 | 
			
		||||
 | 
			
		||||
#include "../../usb_common_types.h"
 | 
			
		||||
 | 
			
		||||
#include "../../usb_driver_common.h"
 | 
			
		||||
 | 
			
		||||
// maximum number of endpoints that can be supported
 | 
			
		||||
#define USB_MAX_NUM_OF_ENDPOINTS (8)
 | 
			
		||||
 | 
			
		||||
// number of supported endpoints
 | 
			
		||||
#ifndef USB_NUM_OF_ENDPOINTS // number of endpoints can be overridden to conserve memory
 | 
			
		||||
#define USB_NUM_OF_ENDPOINTS (USB_MAUSB_MAX_NUM_OF_ENDPOINTS) // set it to the maximum that this type of module can support
 | 
			
		||||
#else
 | 
			
		||||
#if USB_MAX_NUM_OF_ENDPOINTS > USB_MAX_NUM_OF_ENDPOINTS // do not allow greater number of endpoints than what the device supports
 | 
			
		||||
#undef USB_NUM_OF_ENDPOINTS
 | 
			
		||||
#define USB_NUM_OF_ENDPOINTS (USB_MUSB_MAX_NUM_OF_ENDPOINTS)
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// 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 */
 | 
			
		||||
@ -192,14 +192,6 @@ void usbdrv_init_global_state() {
 | 
			
		||||
    gs.rx_buf_level = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Hook for initializing modules after the low-level driver has been initialized
 | 
			
		||||
 * but has not been connected to the bus yet.
 | 
			
		||||
 */
 | 
			
		||||
__weak void usbdrv_init_hook() {
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// initialize USB subsystem
 | 
			
		||||
void usbdrv_init() {
 | 
			
		||||
    USB_IRQ_DISABLE(USB_IRQ_N); // disable USB interrupts
 | 
			
		||||
@ -209,7 +201,6 @@ void usbdrv_init() {
 | 
			
		||||
    usbdrv_gpio_init();
 | 
			
		||||
    usbdrv_periph_init(false);
 | 
			
		||||
    usbdrv_initial_ep0_setup();
 | 
			
		||||
    usbdrv_init_hook(); // <---
 | 
			
		||||
    usbdrv_power_and_connect(true);
 | 
			
		||||
 | 
			
		||||
    USB_IRQ_SET_PRIORITY(USB_IRQ_N, USB_IRQ_PRIORITY);
 | 
			
		||||
 | 
			
		||||
@ -1,38 +0,0 @@
 | 
			
		||||
#ifndef CONFIGS_FLATUSB_CONFIG
 | 
			
		||||
#define CONFIGS_FLATUSB_CONFIG
 | 
			
		||||
#ifndef SRC_FLATUSB_CONFIG
 | 
			
		||||
#define SRC_FLATUSB_CONFIG
 | 
			
		||||
 | 
			
		||||
#include <ch32f20x_usb.h>
 | 
			
		||||
#include <ch32f20x_rcc.h>
 | 
			
		||||
#include <ch32f20x.h>
 | 
			
		||||
 | 
			
		||||
static inline void usbdrv_gpio_init(void) {
 | 
			
		||||
    // turn ON GPIOA clocks
 | 
			
		||||
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define USB_IRQ_N OTG_FS_IRQn
 | 
			
		||||
#define USB_IRQ_HANDLER OTG_FS_IRQHandler
 | 
			
		||||
#define USB_IRQ_PRIORITY (8)
 | 
			
		||||
#define USB_IRQ_SET_PRIORITY(irq, priority) NVIC_SetPriority((irq),(priority))
 | 
			
		||||
#define USB_IRQ_ENABLE(irq) NVIC_EnableIRQ((irq))
 | 
			
		||||
#define USB_IRQ_DISABLE(irq) NVIC_DisableIRQ((irq))
 | 
			
		||||
 | 
			
		||||
// define USBG
 | 
			
		||||
#define USBG (USBOTG_FS)
 | 
			
		||||
 | 
			
		||||
#define USB_CLOCK_ENABLE() RCC_AHBPeriphClockCmd(RCC_AHBPeriph_OTG_FS, ENABLE);\
 | 
			
		||||
                           RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE)
 | 
			
		||||
 | 
			
		||||
#include "embfmt/embformat.h"
 | 
			
		||||
#define SNPRINTF(str, n, fmt, ...) embfmt(str, n, fmt, __VA_ARGS__)
 | 
			
		||||
 | 
			
		||||
#ifdef USBDBGMSG
 | 
			
		||||
#define USBMSG(...) MSG(__VA_ARGS__)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* SRC_FLATUSB_CONFIG */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* CONFIGS_FLATUSB_CONFIG */
 | 
			
		||||
							
								
								
									
										6
									
								
								usb.c
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								usb.c
									
									
									
									
									
								
							@ -271,9 +271,11 @@ void usbcore_process_nonsetup_event(UsbDrv_CallbackCompound *cbcpd) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void usbcore_wake_up_endpoint(uint8_t ep, uint8_t dir) {
 | 
			
		||||
    drv->en_ep_irq(ep, dir, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void usbcore_register_IN_callback(uint8_t ep, UsbDrv_IN_cb cb) {
 | 
			
		||||
    bool en = cb != NULL;
 | 
			
		||||
    drv->en_ep_irq(ep, USB_IN, en);
 | 
			
		||||
    drv->reg_IN_cb(ep, cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										8
									
								
								usb.h
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								usb.h
									
									
									
									
									
								
							@ -60,6 +60,14 @@ uint32_t usbcore_schedule_transmission(uint8_t ep, const uint8_t *data, uint16_t
 | 
			
		||||
 */
 | 
			
		||||
uint32_t usbcore_schedule_reception(uint8_t ep, uint16_t size);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Wake up an Endpoint.
 | 
			
		||||
 *
 | 
			
		||||
 * @param ep index of the Endpoint
 | 
			
		||||
 * @param dir direction of the Endpoint
 | 
			
		||||
 */
 | 
			
		||||
void usbcore_wake_up_endpoint(uint8_t ep, uint8_t dir);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Register a callback for IN transmission completion.
 | 
			
		||||
 *
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user