implement tuh_edpt_xfer() for non-control
This commit is contained in:
@@ -256,7 +256,13 @@ bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance)
|
||||
// claim endpoint
|
||||
TU_VERIFY( usbh_edpt_claim(dev_addr, hid_itf->ep_in) );
|
||||
|
||||
return usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size);
|
||||
if ( !usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size) )
|
||||
{
|
||||
usbh_edpt_claim(dev_addr, hid_itf->ep_in);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance)
|
||||
|
104
src/host/usbh.c
104
src/host/usbh.c
@@ -82,8 +82,7 @@ typedef struct {
|
||||
uint8_t speed;
|
||||
|
||||
// Device State
|
||||
struct TU_ATTR_PACKED
|
||||
{
|
||||
struct TU_ATTR_PACKED {
|
||||
volatile uint8_t connected : 1;
|
||||
volatile uint8_t addressed : 1;
|
||||
volatile uint8_t configured : 1;
|
||||
@@ -110,7 +109,11 @@ typedef struct {
|
||||
tu_edpt_state_t ep_status[CFG_TUH_ENDPOINT_MAX][2];
|
||||
|
||||
#if CFG_TUH_API_EDPT_XFER
|
||||
// ep_xfer[];
|
||||
// TODO array can be CFG_TUH_ENDPOINT_MAX-1
|
||||
struct {
|
||||
tuh_xfer_cb_t complete_cb;
|
||||
uintptr_t user_data;
|
||||
}ep_callback[CFG_TUH_ENDPOINT_MAX][2];
|
||||
#endif
|
||||
|
||||
} usbh_device_t;
|
||||
@@ -227,6 +230,8 @@ TU_ATTR_ALWAYS_INLINE static inline void usbh_unlock(void)
|
||||
|
||||
#else
|
||||
|
||||
#define _usbh_mutex NULL
|
||||
|
||||
#define usbh_lock()
|
||||
#define usbh_unlock()
|
||||
|
||||
@@ -449,10 +454,38 @@ void tuh_task(void)
|
||||
}else
|
||||
{
|
||||
uint8_t drv_id = dev->ep2drv[epnum][ep_dir];
|
||||
TU_ASSERT(drv_id < USBH_CLASS_DRIVER_COUNT, );
|
||||
if(drv_id < USBH_CLASS_DRIVER_COUNT)
|
||||
{
|
||||
TU_LOG2("%s xfer callback\r\n", usbh_class_drivers[drv_id].name);
|
||||
usbh_class_drivers[drv_id].xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if CFG_TUH_API_EDPT_XFER
|
||||
tuh_xfer_cb_t complete_cb = dev->ep_callback[epnum][ep_dir].complete_cb;
|
||||
if ( complete_cb )
|
||||
{
|
||||
tuh_xfer_t xfer =
|
||||
{
|
||||
.daddr = event.dev_addr,
|
||||
.ep_addr = ep_addr,
|
||||
.result = event.xfer_complete.result,
|
||||
.actual_len = event.xfer_complete.len,
|
||||
.buflen = 0, // not available
|
||||
.buffer = NULL, // not available
|
||||
.complete_cb = complete_cb,
|
||||
.user_data = dev->ep_callback[epnum][ep_dir].user_data
|
||||
};
|
||||
|
||||
TU_LOG2("%s xfer callback\r\n", usbh_class_drivers[drv_id].name);
|
||||
usbh_class_drivers[drv_id].xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
|
||||
complete_cb(&xfer);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
// no driver/callback responsible for this transfer
|
||||
TU_ASSERT(false, );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -638,9 +671,18 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result
|
||||
|
||||
bool tuh_edpt_xfer(tuh_xfer_t* xfer)
|
||||
{
|
||||
TU_VERIFY(xfer->daddr && xfer->ep_addr);
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
uint8_t const ep_addr = xfer->ep_addr;
|
||||
|
||||
TU_VERIFY(daddr && ep_addr);
|
||||
|
||||
TU_VERIFY(usbh_edpt_claim(daddr, ep_addr));
|
||||
|
||||
if ( !usbh_edpt_xfer_with_callback(daddr, ep_addr, xfer->buffer, xfer->buflen, xfer->complete_cb, xfer->user_data) )
|
||||
{
|
||||
usbh_edpt_release(daddr, ep_addr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -687,50 +729,50 @@ 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);
|
||||
|
||||
tu_edpt_state_t* ep_state = &dev->ep_status[epnum][dir];
|
||||
|
||||
#if TUSB_OPT_MUTEX
|
||||
return tu_edpt_claim(ep_state, _usbh_mutex);
|
||||
#else
|
||||
return tu_edpt_claim(ep_state, NULL);
|
||||
#endif
|
||||
return tu_edpt_claim(&dev->ep_status[epnum][dir], _usbh_mutex);
|
||||
}
|
||||
|
||||
// TODO has some duplication code with device, refactor later
|
||||
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
// addr0 is always available
|
||||
if (dev_addr == 0) return true;
|
||||
usbh_device_t* dev = get_device(dev_addr);
|
||||
|
||||
usbh_device_t* dev = get_device(dev_addr);
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
tu_edpt_state_t* ep_state = &dev->ep_status[epnum][dir];
|
||||
// addr0 only use tuh_control_xfer
|
||||
TU_ASSERT(dev);
|
||||
|
||||
#if TUSB_OPT_MUTEX
|
||||
return tu_edpt_release(ep_state, _usbh_mutex);
|
||||
#else
|
||||
return tu_edpt_release(ep_state, NULL);
|
||||
#endif
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
return tu_edpt_release(&dev->ep_status[epnum][dir], _usbh_mutex);
|
||||
}
|
||||
|
||||
// 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)
|
||||
bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
|
||||
{
|
||||
(void) complete_cb;
|
||||
(void) user_data;
|
||||
|
||||
usbh_device_t* dev = get_device(dev_addr);
|
||||
TU_VERIFY(dev);
|
||||
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
tu_edpt_state_t* ep_state = &dev->ep_status[epnum][dir];
|
||||
|
||||
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);
|
||||
TU_ASSERT(ep_state->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;
|
||||
ep_state->busy = 1;
|
||||
|
||||
#if CFG_TUH_API_EDPT_XFER
|
||||
dev->ep_callback[epnum][dir].complete_cb = complete_cb;
|
||||
dev->ep_callback[epnum][dir].user_data = user_data;
|
||||
#endif
|
||||
|
||||
if ( hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes) )
|
||||
{
|
||||
@@ -739,9 +781,9 @@ bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_
|
||||
}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_LOG1("failed\r\n");
|
||||
ep_state->busy = 0;
|
||||
ep_state->claimed = 0;
|
||||
TU_LOG1("Failed\r\n");
|
||||
TU_BREAKPOINT();
|
||||
return false;
|
||||
}
|
||||
|
@@ -44,25 +44,27 @@ typedef struct tuh_xfer_s tuh_xfer_t;
|
||||
|
||||
typedef void (*tuh_xfer_cb_t)(tuh_xfer_t* xfer);
|
||||
|
||||
// Note: layout and order of this will be changed in near future
|
||||
// it is advised to initialize it using member name
|
||||
struct tuh_xfer_s
|
||||
{
|
||||
uint8_t daddr;
|
||||
uint8_t ep_addr;
|
||||
|
||||
xfer_result_t result;
|
||||
uint32_t actual_len; // excluding setup packet
|
||||
uint32_t actual_len; // excluding setup packet
|
||||
|
||||
union
|
||||
{
|
||||
tusb_control_request_t const* setup; // setup packet pointer if control transfer
|
||||
uint32_t buflen; // length if not control transfer
|
||||
uint32_t buflen; // expected length if not control transfer (not available in callback)
|
||||
};
|
||||
|
||||
uint8_t* buffer;
|
||||
uint8_t* buffer; // not available in callback if not control transfer
|
||||
tuh_xfer_cb_t complete_cb;
|
||||
uintptr_t user_data;
|
||||
|
||||
uint32_t timeout_ms; // place holder, not supported yet
|
||||
// uint32_t timeout_ms; // place holder, not supported yet
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
@@ -66,8 +66,16 @@ void usbh_int_set(bool enabled);
|
||||
// Open an endpoint
|
||||
bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep);
|
||||
|
||||
// Submit a usb transfer
|
||||
bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
|
||||
// Submit a usb transfer with callback support, require CFG_TUH_API_EDPT_XFER
|
||||
bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE
|
||||
static inline bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
|
||||
{
|
||||
return usbh_edpt_xfer_with_callback(dev_addr, ep_addr, buffer, total_bytes, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
// Claim an endpoint before submitting a transfer.
|
||||
// If caller does not make any transfer, it must release endpoint for others.
|
||||
|
Reference in New Issue
Block a user