/* * The MIT License (MIT) * * Copyright (c) 2024 Ha Thach (tinyusb.org) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * This file is part of the TinyUSB stack. */ #include "tusb_option.h" #if CFG_TUH_ENABLED && defined(TUP_USBIP_DWC2) // Debug level for DWC2 #define DWC2_DEBUG 2 #include "host/hcd.h" #include "dwc2_common.h" //--------------------------------------------------------------------+ // Controller API //--------------------------------------------------------------------+ // optional hcd configuration, called by tuh_configure() bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { (void) rhport; (void) cfg_id; (void) cfg_param; return false; } // Initialize controller to host mode bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { dwc2_regs_t* dwc2 = DWC2_REG(rhport); // Core Initialization TU_ASSERT(dwc2_core_init(rhport, rh_init)); // force host mode dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FDMOD) | GUSBCFG_FHMOD; //------------- 3.1 Host Initialization -------------// // Enable required interrupts dwc2->gintmsk |= GINTMSK_OTGINT | GINTMSK_PRTIM | GINTMSK_WUIM; // max speed if (dwc2_core_is_highspeed(dwc2, rh_init)) { dwc2->hcfg &= ~HCFG_FSLSS; } else { dwc2->hcfg |= HCFG_FSLSS; } // port power on -> drive VBUS dwc2->hprt = HPRT_POWER; return true; } // Enable USB interrupt void hcd_int_enable (uint8_t rhport) { (void) rhport; } // Disable USB interrupt void hcd_int_disable(uint8_t rhport) { (void) rhport; } // Get frame number (1ms) uint32_t hcd_frame_number(uint8_t rhport) { (void) rhport; return 0; } //--------------------------------------------------------------------+ // Port API //--------------------------------------------------------------------+ // Get the current connect status of roothub port bool hcd_port_connect_status(uint8_t rhport) { (void) rhport; return false; } // Reset USB bus on the port. Return immediately, bus reset sequence may not be complete. // Some port would require hcd_port_reset_end() to be invoked after 10ms to complete the reset sequence. void hcd_port_reset(uint8_t rhport) { (void) rhport; } // Complete bus reset sequence, may be required by some controllers void hcd_port_reset_end(uint8_t rhport) { (void) rhport; } // Get port link speed tusb_speed_t hcd_port_speed_get(uint8_t rhport) { (void) rhport; return TUSB_SPEED_FULL; } // HCD closes all opened endpoints belong to this device void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { (void) rhport; (void) dev_addr; } //--------------------------------------------------------------------+ // Endpoints API //--------------------------------------------------------------------+ // Open an endpoint bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) { (void) rhport; (void) dev_addr; (void) ep_desc; return false; } // Submit a transfer, when complete hcd_event_xfer_complete() must be invoked bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { (void) rhport; (void) dev_addr; (void) ep_addr; (void) buffer; (void) buflen; return false; } // Abort a queued transfer. Note: it can only abort transfer that has not been started // Return true if a queued transfer is aborted, false if there is no transfer to abort bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { (void) rhport; (void) dev_addr; (void) ep_addr; return false; } // Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { (void) rhport; (void) dev_addr; (void) setup_packet; return false; } // clear stall, data toggle is also reset to DATA0 bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { (void) rhport; (void) dev_addr; (void) ep_addr; return false; } //-------------------------------------------------------------------- // HCD Event Handler //-------------------------------------------------------------------- /* Interrupt Hierarchy HCINTn.XferCompl HCINTMSKn.XferComplMsk | | +---------- AND --------+ | HAINT.CHn HAINTMSK.CHn | | +---------- AND --------+ | GINTSTS.PrtInt GINTMSK.PrtInt | | +---------- AND --------+ | GAHBCFG.GblIntrMsk | IRQn */ void hcd_int_handler(uint8_t rhport, bool in_isr) { (void) in_isr; dwc2_regs_t* dwc2 = DWC2_REG(rhport); const uint32_t int_mask = dwc2->gintmsk; const uint32_t int_status = dwc2->gintsts & int_mask; if (int_status & GINTSTS_HPRTINT) { TU_LOG1_HEX(dwc2->hprt); } } #endif