split handle channel slave out/in
This commit is contained in:
@@ -1846,9 +1846,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
||||
#define HCINT_XFER_COMPLETE_Pos (0U)
|
||||
#define HCINT_XFER_COMPLETE_Msk (0x1UL << HCINT_XFER_COMPLETE_Pos) // 0x00000001
|
||||
#define HCINT_XFER_COMPLETE HCINT_XFER_COMPLETE_Msk // Transfer completed
|
||||
#define HCINT_CHANNEL_HALTED_Pos (1U)
|
||||
#define HCINT_CHANNEL_HALTED_Msk (0x1UL << HCINT_CHANNEL_HALTED_Pos) // 0x00000002
|
||||
#define HCINT_CHANNEL_HALTED HCINT_CHANNEL_HALTED_Msk // Channel halted
|
||||
#define HCINT_HALTED_Pos (1U)
|
||||
#define HCINT_HALTED_Msk (0x1UL << HCINT_HALTED_Pos) // 0x00000002
|
||||
#define HCINT_HALTED HCINT_HALTED_Msk // Channel halted
|
||||
#define HCINT_AHB_ERR_Pos (2U)
|
||||
#define HCINT_AHB_ERR_Msk (0x1UL << HCINT_AHB_ERR_Pos) // 0x00000004
|
||||
#define HCINT_AHB_ERR HCINT_AHB_ERR_Msk // AHB error
|
||||
|
@@ -55,7 +55,7 @@ enum {
|
||||
enum {
|
||||
HCD_XFER_STATE_UNALLOCATED = 0,
|
||||
HCD_XFER_STATE_ACTIVE = 1,
|
||||
HCD_XFER_STATE_DISABLING = 2,
|
||||
HCD_XFER_STATE_DONE = 2,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
@@ -138,8 +138,16 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t channel_alloc(dwc2_regs_t* dwc2) {
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void channel_dealloc(dwc2_regs_t* dwc2, uint8_t ch_id) {
|
||||
(void) dwc2;
|
||||
_hcd_data.xfer[ch_id].state = HCD_XFER_STATE_UNALLOCATED;
|
||||
dwc2->haintmsk &= ~TU_BIT(ch_id);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void channel_disable(dwc2_channel_t* channel) {
|
||||
channel->hcintmsk |= HCINT_HALTED;
|
||||
|
||||
uint32_t hcchar = channel->hcchar & ~HCCHAR_CHENA; // skip w1s enabled bit
|
||||
hcchar |= HCCHAR_CHDIS;
|
||||
channel->hcchar = hcchar;
|
||||
}
|
||||
|
||||
// Find currently enabled channel. Note: EP0 is bidirectional
|
||||
@@ -661,10 +669,79 @@ TU_ATTR_ALWAYS_INLINE static inline void handle_hprt_irq(uint8_t rhport, bool in
|
||||
dwc2->hprt = hprt; // clear interrupt
|
||||
}
|
||||
|
||||
// DMA related error: HCINT_BUFFER_NA | HCINT_DESC_ROLLOVER
|
||||
// if (hcint & (HCINT_BUFFER_NA | HCINT_DESC_ROLLOVER)) {
|
||||
// result = XFER_RESULT_FAILED;
|
||||
// }
|
||||
xfer_result_t handle_channel_slave_in(dwc2_regs_t* dwc2, uint8_t ch_id, bool is_period, uint32_t hcint) {
|
||||
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
|
||||
dwc2_channel_t* channel = &dwc2->channel[ch_id];
|
||||
xfer_result_t result = XFER_RESULT_INVALID;
|
||||
|
||||
if (hcint & HCINT_XFER_COMPLETE) {
|
||||
result = XFER_RESULT_SUCCESS;
|
||||
channel_disable(channel);
|
||||
channel->hcintmsk &= ~HCINT_ACK;
|
||||
} else if (hcint & (HCINT_XACT_ERR | HCINT_BABBLE_ERR | HCINT_STALL)) {
|
||||
channel_disable(channel);
|
||||
if (hcint & HCINT_XACT_ERR) {
|
||||
xfer->err_count++;
|
||||
channel->hcintmsk |= HCINT_ACK;
|
||||
}
|
||||
} else if (hcint & HCINT_HALTED) {
|
||||
channel->hcintmsk &= ~HCINT_HALTED;
|
||||
if (channel->hcchar_bm.err_multi_count == HCD_XFER_ERROR_MAX) {
|
||||
channel_dealloc(dwc2, ch_id);
|
||||
} else {
|
||||
// Re-initialize Channel
|
||||
}
|
||||
} else if (hcint & HCINT_ACK) {
|
||||
xfer->err_count = 0;
|
||||
channel->hcintmsk &= ~HCINT_ACK;
|
||||
} else if (hcint & HCINT_DATATOGGLE_ERR) {
|
||||
xfer->err_count = 0;
|
||||
} else if (hcint & HCINT_NAK) {
|
||||
// NAK received, re-enable channel if request queue is available
|
||||
TU_ASSERT(request_queue_avail(dwc2, is_period), XFER_RESULT_INVALID);
|
||||
channel->hcchar |= HCCHAR_CHENA;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
xfer_result_t handle_channel_slave_out(dwc2_regs_t* dwc2, uint8_t ch_id, bool is_period, uint32_t hcint) {
|
||||
(void) is_period;
|
||||
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
|
||||
dwc2_channel_t* channel = &dwc2->channel[ch_id];
|
||||
xfer_result_t result = XFER_RESULT_INVALID;
|
||||
|
||||
if (hcint & HCINT_XFER_COMPLETE) {
|
||||
result = XFER_RESULT_SUCCESS;
|
||||
channel->hcintmsk &= ~HCINT_ACK;
|
||||
channel_dealloc(dwc2, ch_id);
|
||||
} else if (hcint & HCINT_STALL) {
|
||||
xfer->state = HCD_XFER_STATE_DONE;
|
||||
channel_disable(channel);
|
||||
} else if (hcint & (HCINT_NAK | HCINT_XACT_ERR | HCINT_NYET)) {
|
||||
channel_disable(channel);
|
||||
if (hcint & HCINT_XACT_ERR) {
|
||||
xfer->err_count++;
|
||||
channel->hcintmsk |= HCINT_ACK;
|
||||
} else {
|
||||
xfer->err_count = 0;
|
||||
}
|
||||
} else if (hcint & HCINT_HALTED) {
|
||||
channel->hcintmsk &= ~HCINT_HALTED;
|
||||
if (xfer->state == HCD_XFER_STATE_DONE || channel->hcchar_bm.err_multi_count == HCD_XFER_ERROR_MAX) {
|
||||
result = (xfer->state == HCD_XFER_STATE_DONE ? XFER_RESULT_STALLED : XFER_RESULT_FAILED);
|
||||
channel_dealloc(dwc2, ch_id);
|
||||
} else {
|
||||
// Re-initialize Channel (Do ping protocol for HS)
|
||||
}
|
||||
} else if (hcint & HCINT_ACK) {
|
||||
xfer->err_count = 0;
|
||||
channel->hcintmsk &= ~HCINT_ACK;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void handle_channel_irq(uint8_t rhport, bool in_isr) {
|
||||
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||
const bool is_dma = dma_host_enabled(dwc2);
|
||||
@@ -674,75 +751,28 @@ void handle_channel_irq(uint8_t rhport, bool in_isr) {
|
||||
if (tu_bit_test(dwc2->haint, ch_id)) {
|
||||
dwc2_channel_t* channel = &dwc2->channel[ch_id];
|
||||
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
|
||||
dwc2_channel_char_t hcchar_bm = channel->hcchar_bm;
|
||||
const bool is_period = edpt_is_periodic(hcchar_bm.ep_type);
|
||||
|
||||
uint32_t hcint = channel->hcint;
|
||||
hcint &= channel->hcintmsk;
|
||||
|
||||
dwc2_channel_char_t hcchar_bm = channel->hcchar_bm;
|
||||
xfer_result_t result = XFER_RESULT_INVALID; // invalid means not DONE
|
||||
|
||||
if (is_dma) {
|
||||
|
||||
} else {
|
||||
if (hcint & HCINT_XFER_COMPLETE) {
|
||||
result = XFER_RESULT_SUCCESS;
|
||||
channel->hcintmsk &= ~HCINT_ACK;
|
||||
channel_dealloc(dwc2, ch_id);
|
||||
} else if (hcint & HCINT_STALL) {
|
||||
result = XFER_RESULT_STALLED;
|
||||
channel->hcintmsk |= HCINT_CHANNEL_HALTED;
|
||||
channel->hcchar_bm.disable = 1;
|
||||
} else if (hcint & (HCINT_NAK | HCINT_XACT_ERR | HCINT_NYET)) {
|
||||
xfer_result_t result;
|
||||
|
||||
if (hcchar_bm.ep_dir == TUSB_DIR_OUT) {
|
||||
// rewind buffer
|
||||
result = handle_channel_slave_out(dwc2, ch_id, is_period, hcint);
|
||||
} else {
|
||||
if (hcint & HCINT_NAK) {
|
||||
// NAK received, re-enable channel if request queue is available
|
||||
TU_ASSERT(request_queue_avail(dwc2, edpt_is_periodic(hcchar_bm.ep_type)), );
|
||||
channel->hcchar |= HCCHAR_CHENA;
|
||||
result = handle_channel_slave_in(dwc2, ch_id, is_period, hcint);
|
||||
}
|
||||
}
|
||||
|
||||
// unmask halted
|
||||
// disable channel
|
||||
if (hcint & HCINT_XACT_ERR) {
|
||||
xfer->err_count++;
|
||||
channel->hcintmsk |= HCINT_ACK;
|
||||
}else {
|
||||
xfer->err_count = 0;
|
||||
}
|
||||
} else if (hcint & HCINT_CHANNEL_HALTED) {
|
||||
if (channel->hcchar_bm.err_multi_count == HCD_XFER_ERROR_MAX) {
|
||||
|
||||
} else {
|
||||
// Re-initialize Channel (Do ping protocol for HS)
|
||||
}
|
||||
} else if (hcint & HCINT_ACK) {
|
||||
// ACK received, reset error count
|
||||
xfer->err_count = 0;
|
||||
channel->hcintmsk &= ~HCINT_ACK;
|
||||
}
|
||||
|
||||
// const uint32_t xact_err = hcint & (HCINT_AHB_ERR | HCINT_XACT_ERR | HCINT_BABBLE_ERR |
|
||||
// HCINT_DATATOGGLE_ERR | HCINT_XCS_XACT_ERR);
|
||||
// if (xact_err) {
|
||||
// result = XFER_RESULT_FAILED;
|
||||
// }
|
||||
// if (!xact_err && (hcint & HCINT_CHANNEL_HALTED)) {
|
||||
// // Channel halted without error, this is a response to channel disable
|
||||
// result = XFER_RESULT_INVALID;
|
||||
// }
|
||||
|
||||
|
||||
// Transfer is complete (success, stalled, failed) or channel is disabled
|
||||
if (result != XFER_RESULT_INVALID || (hcint & HCINT_CHANNEL_HALTED)) {
|
||||
dwc2->haintmsk &= ~TU_BIT(ch_id); // de-allocate channel
|
||||
|
||||
if (result != XFER_RESULT_INVALID ) {
|
||||
// notify usbh if transfer is complete (skip if channel is disabled)
|
||||
const uint8_t ep_addr = tu_edpt_addr(hcchar_bm.ep_num, hcchar_bm.ep_dir);
|
||||
if (result != XFER_RESULT_INVALID) {
|
||||
hcd_event_xfer_complete(hcchar_bm.dev_addr, ep_addr, 0, result, in_isr);
|
||||
}
|
||||
hcd_event_xfer_complete(hcchar_bm.dev_addr, ep_addr, xfer->total_bytes, result, in_isr);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user