|
|
@@ -28,19 +28,30 @@
|
|
|
|
|
|
#if TUSB_OPT_HOST_ENABLED
|
|
|
|
|
|
-#ifndef CFG_TUH_TASK_QUEUE_SZ
|
|
|
-#define CFG_TUH_TASK_QUEUE_SZ 16
|
|
|
-#endif
|
|
|
-
|
|
|
#include "tusb.h"
|
|
|
#include "host/usbh.h"
|
|
|
#include "host/usbh_classdriver.h"
|
|
|
#include "hub.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
|
|
|
//--------------------------------------------------------------------+
|
|
|
+
|
|
|
+// Invalid driver ID in itf2drv[] ep2drv[][] mapping
|
|
|
+enum { DRVID_INVALID = 0xFFu };
|
|
|
+
|
|
|
#if CFG_TUSB_DEBUG >= 2
|
|
|
#define DRIVER_NAME(_name) .name = _name,
|
|
|
#else
|
|
|
@@ -52,7 +63,6 @@ static usbh_class_driver_t const usbh_class_drivers[] =
|
|
|
#if CFG_TUH_CDC
|
|
|
{
|
|
|
DRIVER_NAME("CDC")
|
|
|
- .class_code = TUSB_CLASS_CDC,
|
|
|
.init = cdch_init,
|
|
|
.open = cdch_open,
|
|
|
.set_config = cdch_set_config,
|
|
|
@@ -64,7 +74,6 @@ static usbh_class_driver_t const usbh_class_drivers[] =
|
|
|
#if CFG_TUH_MSC
|
|
|
{
|
|
|
DRIVER_NAME("MSC")
|
|
|
- .class_code = TUSB_CLASS_MSC,
|
|
|
.init = msch_init,
|
|
|
.open = msch_open,
|
|
|
.set_config = msch_set_config,
|
|
|
@@ -76,7 +85,6 @@ static usbh_class_driver_t const usbh_class_drivers[] =
|
|
|
#if CFG_TUH_HID
|
|
|
{
|
|
|
DRIVER_NAME("HID")
|
|
|
- .class_code = TUSB_CLASS_HID,
|
|
|
.init = hidh_init,
|
|
|
.open = hidh_open,
|
|
|
.set_config = hidh_set_config,
|
|
|
@@ -88,7 +96,6 @@ static usbh_class_driver_t const usbh_class_drivers[] =
|
|
|
#if CFG_TUH_HUB
|
|
|
{
|
|
|
DRIVER_NAME("HUB")
|
|
|
- .class_code = TUSB_CLASS_HUB,
|
|
|
.init = hub_init,
|
|
|
.open = hub_open,
|
|
|
.set_config = hub_set_config,
|
|
|
@@ -100,7 +107,6 @@ static usbh_class_driver_t const usbh_class_drivers[] =
|
|
|
#if CFG_TUH_VENDOR
|
|
|
{
|
|
|
DRIVER_NAME("VENDOR")
|
|
|
- .class_code = TUSB_CLASS_VENDOR_SPECIFIC,
|
|
|
.init = cush_init,
|
|
|
.open = cush_open_subtask,
|
|
|
.xfer_cb = cush_isr,
|
|
|
@@ -135,6 +141,7 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _usbh_ctrl_buf[CFG_TUH_EN
|
|
|
//------------- Helper Function Prototypes -------------//
|
|
|
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 bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
|
|
|
|
|
|
// 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);
|
|
|
@@ -195,8 +202,8 @@ bool tuh_init(uint8_t rhport)
|
|
|
TU_ASSERT(dev->mutex);
|
|
|
#endif
|
|
|
|
|
|
- memset(dev->itf2drv, 0xff, sizeof(dev->itf2drv)); // invalid mapping
|
|
|
- memset(dev->ep2drv , 0xff, sizeof(dev->ep2drv )); // invalid mapping
|
|
|
+ memset(dev->itf2drv, DRVID_INVALID, sizeof(dev->itf2drv)); // invalid mapping
|
|
|
+ memset(dev->ep2drv , DRVID_INVALID, sizeof(dev->ep2drv )); // invalid mapping
|
|
|
}
|
|
|
|
|
|
// Class drivers init
|
|
|
@@ -314,151 +321,6 @@ uint8_t* usbh_get_enum_buf(void)
|
|
|
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
|
|
|
//--------------------------------------------------------------------+
|
|
|
@@ -473,7 +335,6 @@ void hcd_event_handler(hcd_event_t const* event, bool in_isr)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// interrupt caused by a TD (with IOC=1) in pipe of class class_code
|
|
|
void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr)
|
|
|
{
|
|
|
hcd_event_t event =
|
|
|
@@ -546,8 +407,8 @@ void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port
|
|
|
usbh_class_drivers[drv_id].close(dev_addr);
|
|
|
}
|
|
|
|
|
|
- memset(dev->itf2drv, 0xff, sizeof(dev->itf2drv)); // invalid mapping
|
|
|
- memset(dev->ep2drv , 0xff, sizeof(dev->ep2drv )); // invalid mapping
|
|
|
+ memset(dev->itf2drv, DRVID_INVALID, sizeof(dev->itf2drv)); // invalid mapping
|
|
|
+ memset(dev->ep2drv , DRVID_INVALID, sizeof(dev->ep2drv )); // invalid mapping
|
|
|
|
|
|
hcd_device_close(rhport, dev_addr);
|
|
|
|
|
|
@@ -576,7 +437,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
|
|
|
{
|
|
|
// continue with next valid interface
|
|
|
uint8_t const drv_id = dev->itf2drv[itf_num];
|
|
|
- if (drv_id != 0xff)
|
|
|
+ if (drv_id != DRVID_INVALID)
|
|
|
{
|
|
|
usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
|
|
|
TU_LOG2("%s set config: itf = %u\r\n", driver->name, itf_num);
|
|
|
@@ -841,7 +702,7 @@ static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t c
|
|
|
dev0->state = TUSB_DEVICE_STATE_UNPLUG;
|
|
|
|
|
|
// 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
|
|
|
TU_LOG2("Get Device Descriptor\r\n");
|
|
|
@@ -972,11 +833,11 @@ static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t co
|
|
|
dev->configured = 1;
|
|
|
dev->state = TUSB_DEVICE_STATE_CONFIGURED;
|
|
|
|
|
|
- // Start the Set Configuration process for interfaces (itf = 0xff)
|
|
|
+ // Start the Set Configuration process for interfaces (itf = DRVID_INVALID)
|
|
|
// Since driver can perform control transfer within its set_config, this is done asynchronously.
|
|
|
// The process continue with next interface when class driver complete its sequence with usbh_driver_set_config_complete()
|
|
|
- // TODO use separated API instead of usig 0xff
|
|
|
- usbh_driver_set_config_complete(dev_addr, 0xff);
|
|
|
+ // TODO use separated API instead of using DRVID_INVALID
|
|
|
+ usbh_driver_set_config_complete(dev_addr, DRVID_INVALID);
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
@@ -992,58 +853,206 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura
|
|
|
while( p_desc < desc_end )
|
|
|
{
|
|
|
// 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
|
|
|
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);
|
|
|
}
|
|
|
|
|
|
TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(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;
|
|
|
|
|
|
- // Check if class is supported TODO drop class_code
|
|
|
- uint8_t drv_id;
|
|
|
- for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
|
|
|
- {
|
|
|
- if ( usbh_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break;
|
|
|
- }
|
|
|
+ // Interface number must not be used already
|
|
|
+ TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == DRVID_INVALID );
|
|
|
|
|
|
- if( drv_id >= USBH_CLASS_DRIVER_COUNT )
|
|
|
+ uint16_t const drv_len = tu_desc_get_interface_total_len(desc_itf, desc_iad ? desc_iad->bInterfaceCount : 1, desc_end-p_desc);
|
|
|
+ TU_ASSERT(drv_len);
|
|
|
+
|
|
|
+ if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0)
|
|
|
{
|
|
|
- // skip unsupported class
|
|
|
- p_desc = tu_desc_next(p_desc);
|
|
|
+ // TODO Attach hub to Hub is not currently supported
|
|
|
+ // skip this interface
|
|
|
+ TU_LOG(USBH_DBG_LVL, "Only 1 level of HUB is supported\r\n");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
|
|
|
+ // Find driver for this interface
|
|
|
+ uint8_t drv_id;
|
|
|
+ for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
|
|
|
+ {
|
|
|
+ usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
|
|
|
|
|
|
- // Interface number must not be used already TODO alternate interface
|
|
|
- TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == 0xff );
|
|
|
- dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id;
|
|
|
+ if ( driver->open(dev->rhport, dev_addr, desc_itf, drv_len) )
|
|
|
+ {
|
|
|
+ // open successfully
|
|
|
+ TU_LOG2("%s opened\r\n", driver->name);
|
|
|
|
|
|
- if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0)
|
|
|
- {
|
|
|
- // TODO Attach hub to Hub is not currently supported
|
|
|
- // skip this interface
|
|
|
- p_desc = tu_desc_next(p_desc);
|
|
|
+ // bind interface to found driver
|
|
|
+ dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id;
|
|
|
+
|
|
|
+ // If using IAD, bind all interfaces to the same driver
|
|
|
+ if (desc_iad)
|
|
|
+ {
|
|
|
+ // IAD's first interface number and class should match with opened interface
|
|
|
+ TU_ASSERT(desc_iad->bFirstInterface == desc_itf->bInterfaceNumber &&
|
|
|
+ desc_iad->bFunctionClass == desc_itf->bInterfaceClass);
|
|
|
+
|
|
|
+ for(uint8_t i=1; i<desc_iad->bInterfaceCount; i++)
|
|
|
+ {
|
|
|
+ dev->itf2drv[desc_itf->bInterfaceNumber+i] = drv_id;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // bind all endpoints to found driver
|
|
|
+ tu_edpt_bind_driver(dev->ep2drv, desc_itf, drv_len, drv_id);
|
|
|
+
|
|
|
+ break; // exit driver find loop
|
|
|
+ }
|
|
|
}
|
|
|
- else
|
|
|
- {
|
|
|
- TU_LOG2("%s open\r\n", driver->name);
|
|
|
|
|
|
- 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);
|
|
|
- p_desc += itf_len;
|
|
|
+ if( drv_id >= USBH_CLASS_DRIVER_COUNT )
|
|
|
+ {
|
|
|
+ TU_LOG(USBH_DBG_LVL, "Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n",
|
|
|
+ desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // next Interface or IAD descriptor
|
|
|
+ p_desc += drv_len;
|
|
|
}
|
|
|
|
|
|
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
|