mirror of
https://github.com/hathach/tinyusb.git
synced 2026-08-18 11:02:16 +00:00
vendor: deactivate de-selected altsetting's isochronous endpoints
vendord_set_alt() aborted bulk/interrupt endpoints of the outgoing altsetting (stall/clear-stall) but only dropped the iso endpoints' tracking: an armed iso transfer stayed live in the dcd with its usbd claim held and no tracked handle to stop it, and its completion fired into an endpoint the class no longer recognizes. Reachable through the usbtest example's alt0 (bulk) <-> alt1 (iso) SET_INTERFACE switching. Track each selected iso endpoint's descriptor (points into the app's static descriptor set) and deactivate on de-selection: with the iso-alloc API re-activation is the abort/scrub primitive (resets ep_status, aborts the stale transfer); without it usbd_edpt_close does, and the next selection re-opens. Iso cannot be stalled like bulk/interrupt, hence the separate path. Build-verified: usbtest for stm32f072disco, ra4m1_ek, raspberry_pi_pico (iso-alloc) and ch32v307v_r1_1v0 (close API).
This commit is contained in:
29
src/class/vendor/vendor_device.c
vendored
29
src/class/vendor/vendor_device.c
vendored
@ -31,9 +31,11 @@ typedef struct {
|
||||
#if CFG_TUD_VENDOR_EP_ISO_OUT
|
||||
uint8_t ep_iso_out;
|
||||
uint16_t iso_rx_xfer_len;
|
||||
const tusb_desc_endpoint_t* iso_out_desc; // for deactivation on altsetting de-selection
|
||||
#endif
|
||||
#if CFG_TUD_VENDOR_EP_ISO_IN
|
||||
uint8_t ep_iso_in;
|
||||
const tusb_desc_endpoint_t* iso_in_desc; // for deactivation on altsetting de-selection
|
||||
#endif
|
||||
#if CFG_TUD_VENDOR_ALT_SETTINGS // implies non-buffered: fields cleared by bus reset
|
||||
uint8_t cur_alt;
|
||||
@ -483,6 +485,21 @@ static inline bool vendord_iso_ep_alloc(uint8_t rhport, const tusb_desc_endpoint
|
||||
#endif
|
||||
}
|
||||
|
||||
// Deactivate a de-selected altsetting's isochronous endpoint: abort any in-flight
|
||||
// transfer and release its usbd claim so a stale completion cannot fire into a
|
||||
// no-longer-tracked endpoint (iso cannot be stalled like bulk/interrupt below). With the
|
||||
// iso-alloc API, (re)activation with the endpoint's descriptor is the abort/scrub
|
||||
// primitive; without it, close does (the next selection re-opens).
|
||||
static inline void vendord_iso_ep_deactivate(uint8_t rhport, const tusb_desc_endpoint_t* desc_ep) {
|
||||
if (desc_ep != NULL) {
|
||||
#ifdef TUP_DCD_EDPT_ISO_ALLOC
|
||||
usbd_edpt_iso_activate(rhport, desc_ep);
|
||||
#else
|
||||
usbd_edpt_close(rhport, desc_ep->bEndpointAddress);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// (Re)activate an isochronous endpoint on altsetting selection.
|
||||
static inline bool vendord_iso_ep_activate(uint8_t rhport, const tusb_desc_endpoint_t* desc_ep) {
|
||||
#ifdef TUP_DCD_EDPT_ISO_ALLOC
|
||||
@ -526,9 +543,9 @@ static bool vendord_set_alt(uint8_t rhport, uint8_t idx, uint8_t alt) {
|
||||
if (in_target_alt && !alt_found) {
|
||||
alt_found = true;
|
||||
// target altsetting confirmed present: abort then drop the previous altsetting's endpoints,
|
||||
// so a bulk/interrupt endpoint absent from the target altsetting can't stay armed and keep
|
||||
// its usbd claim in the dcd. (Endpoints the target altsetting reuses are reset again below;
|
||||
// a double reset is harmless. Iso endpoints are re-activated on reselection.)
|
||||
// so an endpoint absent from the target altsetting can't stay armed and keep its usbd
|
||||
// claim in the dcd. (Endpoints the target altsetting reuses are reset again below;
|
||||
// a double reset is harmless.)
|
||||
vendord_abort_ep(rhport, p_vendor->ep_in);
|
||||
vendord_abort_ep(rhport, p_vendor->ep_out);
|
||||
#if CFG_TUD_VENDOR_EP_INT_OUT
|
||||
@ -546,9 +563,13 @@ static bool vendord_set_alt(uint8_t rhport, uint8_t idx, uint8_t alt) {
|
||||
p_vendor->ep_int_in = 0;
|
||||
#endif
|
||||
#if CFG_TUD_VENDOR_EP_ISO_OUT
|
||||
vendord_iso_ep_deactivate(rhport, p_vendor->iso_out_desc);
|
||||
p_vendor->iso_out_desc = NULL;
|
||||
p_vendor->ep_iso_out = 0;
|
||||
#endif
|
||||
#if CFG_TUD_VENDOR_EP_ISO_IN
|
||||
vendord_iso_ep_deactivate(rhport, p_vendor->iso_in_desc);
|
||||
p_vendor->iso_in_desc = NULL;
|
||||
p_vendor->ep_iso_in = 0;
|
||||
#endif
|
||||
}
|
||||
@ -604,12 +625,14 @@ static bool vendord_set_alt(uint8_t rhport, uint8_t idx, uint8_t alt) {
|
||||
if (is_in) {
|
||||
TU_ASSERT(vendord_iso_ep_activate(rhport, desc_ep));
|
||||
p_vendor->ep_iso_in = ep_addr;
|
||||
p_vendor->iso_in_desc = desc_ep; // points into p_itf_desc (static app descriptor)
|
||||
}
|
||||
#endif
|
||||
#if CFG_TUD_VENDOR_EP_ISO_OUT
|
||||
if (!is_in) {
|
||||
TU_ASSERT(vendord_iso_ep_activate(rhport, desc_ep));
|
||||
p_vendor->ep_iso_out = ep_addr;
|
||||
p_vendor->iso_out_desc = desc_ep; // points into p_itf_desc (static app descriptor)
|
||||
p_vendor->iso_rx_xfer_len = tu_edpt_packet_size(desc_ep);
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user