summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2025-05-15 21:34:53 +0200
committerHiFiPhile <[email protected]>2025-05-15 21:34:53 +0200
commit376c1063b7184984ae44ff5a3d225130bc470d14 (patch)
tree247d4ee97f38ada0e494c065b0d537a66c66ae52 /src
parent90cf575656a009cf4080742909090e219b25ae0f (diff)
Fix transfer failed event still queued
Signed-off-by: HiFiPhile <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/portable/synopsys/dwc2/hcd_dwc2.c33
1 files changed, 31 insertions, 2 deletions
diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c
index 50aa837d2..8821361e8 100644
--- a/src/portable/synopsys/dwc2/hcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/hcd_dwc2.c
@@ -98,6 +98,7 @@ typedef struct {
uint8_t period_split_nyet_count : 3;
uint8_t halted_nyet : 1;
uint8_t halted_sof_schedule : 1;
+ uint8_t closing : 1; // closing channel
};
uint8_t result;
@@ -452,8 +453,12 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
if (xfer->allocated && xfer->ep_id == i) {
dwc2_channel_t* channel = &dwc2->channel[ch_id];
- xfer->err_count = HCD_XFER_ERROR_MAX;
- channel_disable(dwc2, channel);
+ dwc2_channel_split_t hcsplt = {.value = channel->hcsplt};
+ xfer->closing = 1;
+ // Channel disable must not be programmed for non-split periodic channels
+ if (!channel_is_periodic(channel->hcchar) || hcsplt.split_en) {
+ channel_disable(dwc2, channel);
+ }
}
}
}
@@ -915,6 +920,11 @@ static bool handle_channel_in_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t h
} else if (xfer->err_count == HCD_XFER_ERROR_MAX) {
xfer->result = XFER_RESULT_FAILED;
is_done = true;
+ } else if (xfer->closing) {
+ // channel is closing, de-allocate channel
+ channel_dealloc(dwc2, ch_id);
+ // don't send event
+ is_done = false;
} else {
// got here due to NAK or NYET
channel_xfer_in_retry(dwc2, ch_id, hcint);
@@ -969,6 +979,11 @@ static bool handle_channel_out_slave(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t
} else if (xfer->err_count == HCD_XFER_ERROR_MAX) {
xfer->result = XFER_RESULT_FAILED;
is_done = true;
+ } else if (xfer->closing) {
+ // channel is closing, de-allocate channel
+ channel_dealloc(dwc2, ch_id);
+ // don't send event
+ is_done = false;
} else {
// Got here due to NAK or NYET
TU_ASSERT(channel_xfer_start(dwc2, ch_id));
@@ -1068,6 +1083,13 @@ static bool handle_channel_in_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hci
// retry start-split in next binterval
channel_xfer_in_retry(dwc2, ch_id, hcint);
}
+
+ if (xfer->closing) {
+ // channel is closing, de-allocate channel
+ channel_dealloc(dwc2, ch_id);
+ // don't send event
+ is_done = false;
+ }
}
return is_done;
@@ -1125,6 +1147,13 @@ static bool handle_channel_out_dma(dwc2_regs_t* dwc2, uint8_t ch_id, uint32_t hc
channel->hcchar |= HCCHAR_CHENA;
}
}
+
+ if (xfer->closing) {
+ // channel is closing, de-allocate channel
+ channel_dealloc(dwc2, ch_id);
+ // don't send event
+ is_done = false;
+ }
} else if (hcint & HCINT_ACK) {
xfer->err_count = 0;
channel->hcintmsk &= ~HCINT_ACK;