#include "usb_drv.h" #include #include #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) + 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_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; }