/* * The MIT License (MIT) * * Copyright (c) 2019 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 || CFG_TUD_ENABLED #include "tusb.h" #include "common/tusb_private.h" // TODO clean up #if CFG_TUD_ENABLED #include "device/usbd_pvt.h" #endif bool tusb_init(void) { #if CFG_TUD_ENABLED && defined(TUD_OPT_RHPORT) // init device stack CFG_TUSB_RHPORTx_MODE must be defined TU_ASSERT ( tud_init(TUD_OPT_RHPORT) ); #endif #if CFG_TUH_ENABLED && defined(TUH_OPT_RHPORT) // init host stack CFG_TUSB_RHPORTx_MODE must be defined TU_ASSERT( tuh_init(TUH_OPT_RHPORT) ); #endif return true; } bool tusb_inited(void) { bool ret = false; #if CFG_TUD_ENABLED ret = ret || tud_inited(); #endif #if CFG_TUH_ENABLED ret = ret || tuh_inited(); #endif return ret; } //--------------------------------------------------------------------+ // Internal Helper for both Host and Device stack //--------------------------------------------------------------------+ bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex) { (void) mutex; #if TUSB_OPT_MUTEX // pre-check to help reducing mutex lock TU_VERIFY((ep_state->busy == 0) && (ep_state->claimed == 0)); osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); #endif // can only claim the endpoint if it is not busy and not claimed yet. bool const available = (ep_state->busy == 0) && (ep_state->claimed == 0); if (available) { ep_state->claimed = 1; } #if TUSB_OPT_MUTEX osal_mutex_unlock(mutex); #endif return available; } bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex) { (void) mutex; #if TUSB_OPT_MUTEX osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER); #endif // can only release the endpoint if it is claimed and not busy bool const ret = (ep_state->claimed == 1) && (ep_state->busy == 0); if (ret) { ep_state->claimed = 0; } #if TUSB_OPT_MUTEX osal_mutex_unlock(mutex); #endif return ret; } bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed) { uint16_t const max_packet_size = tu_edpt_packet_size(desc_ep); TU_LOG2(" Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, max_packet_size); switch (desc_ep->bmAttributes.xfer) { case TUSB_XFER_ISOCHRONOUS: { uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 1023); TU_ASSERT(max_packet_size <= spec_size); } break; case TUSB_XFER_BULK: if (speed == TUSB_SPEED_HIGH) { // Bulk highspeed must be EXACTLY 512 TU_ASSERT(max_packet_size == 512); }else { // TODO Bulk fullspeed can only be 8, 16, 32, 64 TU_ASSERT(max_packet_size <= 64); } break; case TUSB_XFER_INTERRUPT: { uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 64); TU_ASSERT(max_packet_size <= spec_size); } break; default: return false; } return true; } void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* desc_itf, uint16_t desc_len, uint8_t driver_id) { uint8_t const* p_desc = (uint8_t const*) desc_itf; uint8_t const* desc_end = p_desc + desc_len; while( p_desc < desc_end ) { if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) { uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress; TU_LOG(2, " Bind EP %02x to driver id %u\r\n", ep_addr, driver_id); ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id; } p_desc = tu_desc_next(p_desc); } } uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len) { uint8_t const* p_desc = (uint8_t const*) desc_itf; uint16_t len = 0; while (itf_count--) { // Next on interface desc len += tu_desc_len(desc_itf); p_desc = tu_desc_next(p_desc); while (len < max_len) { // return on IAD regardless of itf count if ( tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION ) return len; if ( (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) && ((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0 ) { break; } len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); } } return len; } /*------------------------------------------------------------------*/ /* Debug *------------------------------------------------------------------*/ #if CFG_TUSB_DEBUG #include #if CFG_TUSB_DEBUG >= 2 char const* const tu_str_speed[] = { "Full", "Low", "High" }; char const* const tu_str_std_request[] = { "Get Status" , "Clear Feature" , "Reserved" , "Set Feature" , "Reserved" , "Set Address" , "Get Descriptor" , "Set Descriptor" , "Get Configuration" , "Set Configuration" , "Get Interface" , "Set Interface" , "Synch Frame" }; #endif static void dump_str_line(uint8_t const* buf, uint16_t count) { tu_printf(" |"); // each line is 16 bytes for(uint16_t i=0; i