mirror of
https://github.com/hathach/tinyusb.git
synced 2025-04-16 05:42:56 +00:00
extra common edpt helper for device and host stack
tu_edpt_validate() and tu_edpt_bind_driver()
This commit is contained in:
parent
aab133ac69
commit
1cef2b6a42
@ -73,6 +73,20 @@
|
|||||||
#include "tusb_error.h" // TODO remove
|
#include "tusb_error.h" // TODO remove
|
||||||
#include "tusb_timeout.h" // TODO remove
|
#include "tusb_timeout.h" // TODO remove
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Internal Helper used by Host and Device Stack
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// Check if endpoint descriptor is valid per USB specs
|
||||||
|
bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed);
|
||||||
|
|
||||||
|
// Bind all endpoint of a interface descriptor to class driver
|
||||||
|
void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Internal Inline Functions
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
//------------- Mem -------------//
|
//------------- Mem -------------//
|
||||||
#define tu_memclr(buffer, size) memset((buffer), 0, (size))
|
#define tu_memclr(buffer, size) memset((buffer), 0, (size))
|
||||||
#define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var)))
|
#define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var)))
|
||||||
|
@ -274,7 +274,6 @@ static osal_mutex_t _usbd_mutex;
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Prototypes
|
// Prototypes
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
static void mark_interface_endpoint(uint8_t ep2drv[][2], uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
|
|
||||||
static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
|
static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
|
||||||
static bool process_set_config(uint8_t rhport, uint8_t cfg_num);
|
static bool process_set_config(uint8_t rhport, uint8_t cfg_num);
|
||||||
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request);
|
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request);
|
||||||
@ -901,7 +900,8 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_interface_endpoint(_usbd_dev.ep2drv, p_desc, drv_len, drv_id); // TODO refactor
|
// bind all endpoints for this driver
|
||||||
|
tu_edpt_bind_driver(_usbd_dev.ep2drv, desc_itf, drv_len, drv_id);
|
||||||
|
|
||||||
p_desc += drv_len; // next interface
|
p_desc += drv_len; // next interface
|
||||||
|
|
||||||
@ -919,25 +919,6 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper marking endpoint of interface belongs to class driver
|
|
||||||
static void mark_interface_endpoint(uint8_t ep2drv[][2], uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id)
|
|
||||||
{
|
|
||||||
uint16_t len = 0;
|
|
||||||
|
|
||||||
while( len < desc_len )
|
|
||||||
{
|
|
||||||
if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
|
|
||||||
{
|
|
||||||
uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress;
|
|
||||||
|
|
||||||
ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = (uint16_t)(len + tu_desc_len(p_desc));
|
|
||||||
p_desc = tu_desc_next(p_desc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return descriptor's buffer and update desc_len
|
// return descriptor's buffer and update desc_len
|
||||||
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request)
|
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||||
{
|
{
|
||||||
@ -1177,41 +1158,8 @@ void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr)
|
|||||||
|
|
||||||
bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep)
|
bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep)
|
||||||
{
|
{
|
||||||
uint16_t const max_packet_size = tu_le16toh(desc_ep->wMaxPacketSize.size);
|
|
||||||
|
|
||||||
TU_LOG2(" Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, max_packet_size);
|
|
||||||
TU_ASSERT(tu_edpt_number(desc_ep->bEndpointAddress) < CFG_TUD_ENDPPOINT_MAX);
|
TU_ASSERT(tu_edpt_number(desc_ep->bEndpointAddress) < CFG_TUD_ENDPPOINT_MAX);
|
||||||
|
TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed));
|
||||||
switch (desc_ep->bmAttributes.xfer)
|
|
||||||
{
|
|
||||||
case TUSB_XFER_ISOCHRONOUS:
|
|
||||||
{
|
|
||||||
uint16_t const spec_size = (_usbd_dev.speed == TUSB_SPEED_HIGH ? 1024 : 1023);
|
|
||||||
TU_ASSERT(max_packet_size <= spec_size);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TUSB_XFER_BULK:
|
|
||||||
if (_usbd_dev.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 = (_usbd_dev.speed == TUSB_SPEED_HIGH ? 1024 : 64);
|
|
||||||
TU_ASSERT(max_packet_size <= spec_size);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dcd_edpt_open(rhport, desc_ep);
|
return dcd_edpt_open(rhport, desc_ep);
|
||||||
}
|
}
|
||||||
|
338
src/host/usbh.c
338
src/host/usbh.c
@ -28,16 +28,23 @@
|
|||||||
|
|
||||||
#if TUSB_OPT_HOST_ENABLED
|
#if TUSB_OPT_HOST_ENABLED
|
||||||
|
|
||||||
#ifndef CFG_TUH_TASK_QUEUE_SZ
|
|
||||||
#define CFG_TUH_TASK_QUEUE_SZ 16
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "tusb.h"
|
#include "tusb.h"
|
||||||
#include "host/usbh.h"
|
#include "host/usbh.h"
|
||||||
#include "host/usbh_classdriver.h"
|
#include "host/usbh_classdriver.h"
|
||||||
#include "hub.h"
|
#include "hub.h"
|
||||||
#include "usbh_hcd.h"
|
#include "usbh_hcd.h"
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// USBH Configuration
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
#ifndef CFG_TUH_TASK_QUEUE_SZ
|
||||||
|
#define CFG_TUH_TASK_QUEUE_SZ 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Debug level of USBD
|
||||||
|
#define USBH_DBG_LVL 2
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// MACRO CONSTANT TYPEDEF
|
// MACRO CONSTANT TYPEDEF
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
@ -135,6 +142,7 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _usbh_ctrl_buf[CFG_TUH_EN
|
|||||||
//------------- Helper Function Prototypes -------------//
|
//------------- Helper Function Prototypes -------------//
|
||||||
static bool enum_new_device(hcd_event_t* event);
|
static bool enum_new_device(hcd_event_t* event);
|
||||||
static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
|
static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
|
||||||
|
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
|
||||||
|
|
||||||
// from usbh_control.c
|
// from usbh_control.c
|
||||||
extern bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
|
extern bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
|
||||||
@ -314,151 +322,6 @@ uint8_t* usbh_get_enum_buf(void)
|
|||||||
return _usbh_ctrl_buf;
|
return _usbh_ctrl_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
// Endpoint API
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
|
|
||||||
// TODO has some duplication code with device, refactor later
|
|
||||||
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
|
|
||||||
{
|
|
||||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
|
||||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
|
||||||
|
|
||||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
|
||||||
|
|
||||||
#if CFG_TUSB_OS != OPT_OS_NONE
|
|
||||||
// pre-check to help reducing mutex lock
|
|
||||||
TU_VERIFY((dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 0));
|
|
||||||
osal_mutex_lock(dev->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// can only claim the endpoint if it is not busy and not claimed yet.
|
|
||||||
bool const ret = (dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 0);
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
dev->ep_status[epnum][dir].claimed = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CFG_TUSB_OS != OPT_OS_NONE
|
|
||||||
osal_mutex_unlock(dev->mutex);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO has some duplication code with device, refactor later
|
|
||||||
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
|
|
||||||
{
|
|
||||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
|
||||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
|
||||||
|
|
||||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
|
||||||
|
|
||||||
#if CFG_TUSB_OS != OPT_OS_NONE
|
|
||||||
osal_mutex_lock(dev->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// can only release the endpoint if it is claimed and not busy
|
|
||||||
bool const ret = (dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 1);
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
dev->ep_status[epnum][dir].claimed = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CFG_TUSB_OS != OPT_OS_NONE
|
|
||||||
osal_mutex_unlock(dev->mutex);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO has some duplication code with device, refactor later
|
|
||||||
bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
|
|
||||||
{
|
|
||||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
|
||||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
|
||||||
|
|
||||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
|
||||||
|
|
||||||
TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes);
|
|
||||||
|
|
||||||
// Attempt to transfer on a busy endpoint, sound like an race condition !
|
|
||||||
TU_ASSERT(dev->ep_status[epnum][dir].busy == 0);
|
|
||||||
|
|
||||||
// Set busy first since the actual transfer can be complete before hcd_edpt_xfer()
|
|
||||||
// could return and USBH task can preempt and clear the busy
|
|
||||||
dev->ep_status[epnum][dir].busy = true;
|
|
||||||
|
|
||||||
if ( hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes) )
|
|
||||||
{
|
|
||||||
TU_LOG2("OK\r\n");
|
|
||||||
return true;
|
|
||||||
}else
|
|
||||||
{
|
|
||||||
// HCD error, mark endpoint as ready to allow next transfer
|
|
||||||
dev->ep_status[epnum][dir].busy = false;
|
|
||||||
dev->ep_status[epnum][dir].claimed = 0;
|
|
||||||
TU_LOG2("failed\r\n");
|
|
||||||
TU_BREAKPOINT();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size)
|
|
||||||
{
|
|
||||||
TU_LOG2("Open EP Control with Size = %u\r\n", max_packet_size);
|
|
||||||
|
|
||||||
tusb_desc_endpoint_t ep0_desc =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(tusb_desc_endpoint_t),
|
|
||||||
.bDescriptorType = TUSB_DESC_ENDPOINT,
|
|
||||||
.bEndpointAddress = 0,
|
|
||||||
.bmAttributes = { .xfer = TUSB_XFER_CONTROL },
|
|
||||||
.wMaxPacketSize = { .size = max_packet_size },
|
|
||||||
.bInterval = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
return hcd_edpt_open(_usbh_devices[dev_addr].rhport, dev_addr, &ep0_desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep)
|
|
||||||
{
|
|
||||||
TU_LOG2(" Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, desc_ep->wMaxPacketSize.size);
|
|
||||||
|
|
||||||
bool ret = hcd_edpt_open(rhport, dev_addr, desc_ep);
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
|
||||||
|
|
||||||
// new endpoints belongs to latest interface (last valid value)
|
|
||||||
// TODO FIXME not true with ISO
|
|
||||||
uint8_t drvid = 0xff;
|
|
||||||
for(uint8_t i=0; i < sizeof(dev->itf2drv); i++)
|
|
||||||
{
|
|
||||||
if ( dev->itf2drv[i] == 0xff ) break;
|
|
||||||
drvid = dev->itf2drv[i];
|
|
||||||
}
|
|
||||||
TU_ASSERT(drvid < USBH_CLASS_DRIVER_COUNT);
|
|
||||||
|
|
||||||
uint8_t const ep_addr = desc_ep->bEndpointAddress;
|
|
||||||
dev->ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = drvid;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
|
|
||||||
{
|
|
||||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
|
||||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
|
||||||
|
|
||||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
|
||||||
|
|
||||||
return dev->ep_status[epnum][dir].busy;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// HCD Event Handler
|
// HCD Event Handler
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
@ -841,7 +704,7 @@ static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t c
|
|||||||
dev0->state = TUSB_DEVICE_STATE_UNPLUG;
|
dev0->state = TUSB_DEVICE_STATE_UNPLUG;
|
||||||
|
|
||||||
// open control pipe for new address
|
// open control pipe for new address
|
||||||
TU_ASSERT ( usbh_edpt_control_open(new_addr, new_dev->ep0_packet_size) );
|
TU_ASSERT( usbh_edpt_control_open(new_addr, new_dev->ep0_packet_size) );
|
||||||
|
|
||||||
// Get full device descriptor
|
// Get full device descriptor
|
||||||
TU_LOG2("Get Device Descriptor\r\n");
|
TU_LOG2("Get Device Descriptor\r\n");
|
||||||
@ -981,6 +844,34 @@ static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t co
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get total length of n interface (depending on IAD)
|
||||||
|
static uint16_t get_interface_length(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;
|
||||||
|
}
|
||||||
|
|
||||||
static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg)
|
static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg)
|
||||||
{
|
{
|
||||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||||
@ -992,20 +883,25 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura
|
|||||||
while( p_desc < desc_end )
|
while( p_desc < desc_end )
|
||||||
{
|
{
|
||||||
// TODO Do we need to use IAD
|
// TODO Do we need to use IAD
|
||||||
// tusb_desc_interface_assoc_t const * desc_itf_assoc = NULL;
|
tusb_desc_interface_assoc_t const * desc_iad = NULL;
|
||||||
|
|
||||||
// Class will always starts with Interface Association (if any) and then Interface descriptor
|
// Class will always starts with Interface Association (if any) and then Interface descriptor
|
||||||
if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
|
if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
|
||||||
{
|
{
|
||||||
// desc_itf_assoc = (tusb_desc_interface_assoc_t const *) p_desc;
|
desc_iad = (tusb_desc_interface_assoc_t const *) p_desc;
|
||||||
p_desc = tu_desc_next(p_desc);
|
p_desc = tu_desc_next(p_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TU_LOG_INT(2, p_desc - (uint8_t*) desc_cfg);
|
||||||
|
TU_LOG_INT(2, tu_desc_type(p_desc));
|
||||||
TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) );
|
TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) );
|
||||||
|
|
||||||
tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
|
tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
|
||||||
uint16_t const remaining_len = desc_end-p_desc;
|
uint16_t const remaining_len = desc_end-p_desc;
|
||||||
|
|
||||||
|
uint16_t const drv_len = get_interface_length(desc_itf, desc_iad ? desc_iad->bInterfaceCount : 1, remaining_len);
|
||||||
|
TU_ASSERT(drv_len);
|
||||||
|
|
||||||
// Check if class is supported TODO drop class_code
|
// Check if class is supported TODO drop class_code
|
||||||
uint8_t drv_id;
|
uint8_t drv_id;
|
||||||
for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
|
for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
|
||||||
@ -1015,8 +911,11 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura
|
|||||||
|
|
||||||
if( drv_id >= USBH_CLASS_DRIVER_COUNT )
|
if( drv_id >= USBH_CLASS_DRIVER_COUNT )
|
||||||
{
|
{
|
||||||
// skip unsupported class
|
TU_LOG(USBH_DBG_LVL, "Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n",
|
||||||
p_desc = tu_desc_next(p_desc);
|
desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol);
|
||||||
|
|
||||||
|
// skip unsupported class until next Interface or IAD descriptor
|
||||||
|
p_desc += drv_len;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1038,6 +937,10 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura
|
|||||||
|
|
||||||
uint16_t const itf_len = driver->open(dev->rhport, dev_addr, desc_itf, remaining_len);
|
uint16_t const itf_len = driver->open(dev->rhport, dev_addr, desc_itf, remaining_len);
|
||||||
TU_ASSERT( sizeof(tusb_desc_interface_t) <= itf_len && itf_len <= remaining_len);
|
TU_ASSERT( sizeof(tusb_desc_interface_t) <= itf_len && itf_len <= remaining_len);
|
||||||
|
|
||||||
|
// bind all endpoints for this driver
|
||||||
|
tu_edpt_bind_driver(dev->ep2drv, desc_itf, drv_len, drv_id);
|
||||||
|
|
||||||
p_desc += itf_len;
|
p_desc += itf_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1046,4 +949,131 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Endpoint API
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// TODO has some duplication code with device, refactor later
|
||||||
|
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
|
||||||
|
{
|
||||||
|
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||||
|
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||||
|
|
||||||
|
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||||
|
|
||||||
|
#if CFG_TUSB_OS != OPT_OS_NONE
|
||||||
|
// pre-check to help reducing mutex lock
|
||||||
|
TU_VERIFY((dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 0));
|
||||||
|
osal_mutex_lock(dev->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// can only claim the endpoint if it is not busy and not claimed yet.
|
||||||
|
bool const ret = (dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 0);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
dev->ep_status[epnum][dir].claimed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CFG_TUSB_OS != OPT_OS_NONE
|
||||||
|
osal_mutex_unlock(dev->mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO has some duplication code with device, refactor later
|
||||||
|
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
|
||||||
|
{
|
||||||
|
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||||
|
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||||
|
|
||||||
|
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||||
|
|
||||||
|
#if CFG_TUSB_OS != OPT_OS_NONE
|
||||||
|
osal_mutex_lock(dev->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// can only release the endpoint if it is claimed and not busy
|
||||||
|
bool const ret = (dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 1);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
dev->ep_status[epnum][dir].claimed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CFG_TUSB_OS != OPT_OS_NONE
|
||||||
|
osal_mutex_unlock(dev->mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO has some duplication code with device, refactor later
|
||||||
|
bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
|
||||||
|
{
|
||||||
|
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||||
|
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||||
|
|
||||||
|
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||||
|
|
||||||
|
TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes);
|
||||||
|
|
||||||
|
// Attempt to transfer on a busy endpoint, sound like an race condition !
|
||||||
|
TU_ASSERT(dev->ep_status[epnum][dir].busy == 0);
|
||||||
|
|
||||||
|
// Set busy first since the actual transfer can be complete before hcd_edpt_xfer()
|
||||||
|
// could return and USBH task can preempt and clear the busy
|
||||||
|
dev->ep_status[epnum][dir].busy = true;
|
||||||
|
|
||||||
|
if ( hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes) )
|
||||||
|
{
|
||||||
|
TU_LOG2("OK\r\n");
|
||||||
|
return true;
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
// HCD error, mark endpoint as ready to allow next transfer
|
||||||
|
dev->ep_status[epnum][dir].busy = false;
|
||||||
|
dev->ep_status[epnum][dir].claimed = 0;
|
||||||
|
TU_LOG2("failed\r\n");
|
||||||
|
TU_BREAKPOINT();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size)
|
||||||
|
{
|
||||||
|
TU_LOG2("Open EP Control with Size = %u\r\n", max_packet_size);
|
||||||
|
|
||||||
|
tusb_desc_endpoint_t ep0_desc =
|
||||||
|
{
|
||||||
|
.bLength = sizeof(tusb_desc_endpoint_t),
|
||||||
|
.bDescriptorType = TUSB_DESC_ENDPOINT,
|
||||||
|
.bEndpointAddress = 0,
|
||||||
|
.bmAttributes = { .xfer = TUSB_XFER_CONTROL },
|
||||||
|
.wMaxPacketSize = { .size = max_packet_size },
|
||||||
|
.bInterval = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
return hcd_edpt_open(_usbh_devices[dev_addr].rhport, dev_addr, &ep0_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep)
|
||||||
|
{
|
||||||
|
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||||
|
TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) dev->speed));
|
||||||
|
|
||||||
|
return hcd_edpt_open(rhport, dev_addr, desc_ep);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
|
||||||
|
{
|
||||||
|
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||||
|
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||||
|
|
||||||
|
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||||
|
|
||||||
|
return dev->ep_status[epnum][dir].busy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -73,6 +73,8 @@ bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_
|
|||||||
// If caller does not make any transfer, it must release endpoint for others.
|
// If caller does not make any transfer, it must release endpoint for others.
|
||||||
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr);
|
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr);
|
||||||
|
|
||||||
|
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr);
|
||||||
|
|
||||||
// Check if endpoint transferring is complete
|
// Check if endpoint transferring is complete
|
||||||
bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr);
|
bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr);
|
||||||
|
|
||||||
|
62
src/tusb.c
62
src/tusb.c
@ -63,6 +63,68 @@ bool tusb_inited(void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Internal Helper for both Host and Device stack
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed)
|
||||||
|
{
|
||||||
|
uint16_t const max_packet_size = tu_le16toh(desc_ep->wMaxPacketSize.size);
|
||||||
|
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;
|
||||||
|
uint16_t len = 0;
|
||||||
|
|
||||||
|
while( len < desc_len )
|
||||||
|
{
|
||||||
|
if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
|
||||||
|
{
|
||||||
|
uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress;
|
||||||
|
|
||||||
|
ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = (uint16_t)(len + tu_desc_len(p_desc));
|
||||||
|
p_desc = tu_desc_next(p_desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------*/
|
/*------------------------------------------------------------------*/
|
||||||
/* Debug
|
/* Debug
|
||||||
*------------------------------------------------------------------*/
|
*------------------------------------------------------------------*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user