fix pid token calculation, implement hcd_edpt_clear_stall(). msc explorer example read work, but write10 still wip

This commit is contained in:
hathach
2024-10-29 21:54:21 +07:00
parent 074811c251
commit 616b5770f2
2 changed files with 47 additions and 22 deletions

View File

@@ -139,10 +139,13 @@ enum {
};
enum {
HCTSIZ_PID_DATA0 = 0,
HCTSIZ_PID_DATA2 = 1,
HCTSIZ_PID_DATA1 = 2,
HCTSIZ_PID_SETUP = 3,
HCTSIZ_PID_DATA0 = 0, // 00b
HCTSIZ_PID_DATA2 = 1, // 01b
HCTSIZ_PID_DATA1 = 2, // 10b
HCTSIZ_PID_SETUP = 3, // 11b
};
enum {
HCTSIZ_PID_MDATA = 3,
};
enum {

View File

@@ -67,13 +67,14 @@ typedef struct {
dwc2_channel_split_t hcsplt_bm;
};
uint8_t next_data_toggle;
uint8_t next_pid;
// uint8_t resv[3];
} hcd_endpoint_t;
// Additional info for each channel when it is active
typedef struct {
volatile bool allocated;
uint8_t ep_id; // associated edpt
uint8_t result;
uint8_t err_count;
uint8_t* buffer;
@@ -125,7 +126,8 @@ 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) {
_hcd_data.xfer[ch_id].allocated = false;
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
xfer->allocated = false;
dwc2->haintmsk &= ~TU_BIT(ch_id);
}
@@ -195,6 +197,14 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t edpt_find_opened(uint8_t dev_addr, u
return TUSB_INDEX_INVALID_8;
}
TU_ATTR_ALWAYS_INLINE static inline uint8_t cal_next_pid(uint8_t pid, uint8_t packet_count) {
if (packet_count & 0x01) {
return pid ^ 0x02; // toggle DATA0 and DATA1
} else {
return pid;
}
}
//--------------------------------------------------------------------
//
//--------------------------------------------------------------------
@@ -322,7 +332,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
// force host mode and wait for mode switch
dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FDMOD) | GUSBCFG_FHMOD;
while( (dwc2->gintsts & GINTSTS_CMOD) != GINTSTS_CMODE_HOST) {}
while ((dwc2->gintsts & GINTSTS_CMOD) != GINTSTS_CMODE_HOST) {}
// configure fixed-allocated fifo scheme
dfifo_host_init(rhport);
@@ -438,7 +448,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t*
hcsplt_bm->split_compl = 0;
hcsplt_bm->split_en = 0;
edpt->next_data_toggle = HCTSIZ_PID_DATA0;
edpt->next_pid = HCTSIZ_PID_DATA0;
return true;
}
@@ -448,6 +458,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
const uint8_t ep_num = tu_edpt_number(ep_addr);
const uint8_t ep_dir = tu_edpt_dir(ep_addr);
uint8_t ep_id = edpt_find_opened(dev_addr, ep_num, ep_dir);
TU_ASSERT(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX);
hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
@@ -456,19 +467,21 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
uint8_t ch_id = channel_alloc(dwc2);
TU_ASSERT(ch_id < 16); // all channel are in used
hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id];
xfer->ep_id = ep_id;
dwc2_channel_t* channel = &dwc2->channel[ch_id];
uint16_t packet_count = tu_div_ceil(buflen, hcchar_bm->ep_size);
if (packet_count == 0) {
packet_count = 1; // zero length packet still count as 1
}
channel->hctsiz = (edpt->next_data_toggle << HCTSIZ_PID_Pos) | (packet_count << HCTSIZ_PKTCNT_Pos) | buflen;
channel->hctsiz = (edpt->next_pid << HCTSIZ_PID_Pos) | (packet_count << HCTSIZ_PKTCNT_Pos) | buflen;
// Control transfer always start with DATA1 for data and status stage. May has issue with ZLP
if (edpt->next_data_toggle == HCTSIZ_PID_DATA0 || ep_num == 0) {
edpt->next_data_toggle = HCTSIZ_PID_DATA1;
// pre-calculate next PID based on packet count, adjusted in transfer complete interrupt if short packet
if (ep_num == 0) {
edpt->next_pid = HCTSIZ_PID_DATA1; // control data and status stage always start with DATA1
} else {
edpt->next_data_toggle = HCTSIZ_PID_DATA0;
edpt->next_pid = cal_next_pid(edpt->next_pid, packet_count);
}
// TODO support split transaction
@@ -546,7 +559,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, const uint8_t setup_packet
uint8_t ep_id = edpt_find_opened(dev_addr, 0, TUSB_DIR_OUT);
TU_ASSERT(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX); // no opened endpoint
hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
edpt->next_data_toggle = HCTSIZ_PID_SETUP;
edpt->next_pid = HCTSIZ_PID_SETUP;
return hcd_edpt_xfer(rhport, dev_addr, 0, (uint8_t*)(uintptr_t) setup_packet, 8);
}
@@ -554,10 +567,15 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, const uint8_t setup_packet
// clear stall, data toggle is also reset to DATA0
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
(void) rhport;
(void) dev_addr;
(void) ep_addr;
const uint8_t ep_num = tu_edpt_number(ep_addr);
const uint8_t ep_dir = tu_edpt_dir(ep_addr);
const uint8_t ep_id = edpt_find_opened(dev_addr, ep_num, ep_dir);
TU_VERIFY(ep_id < CFG_TUH_DWC2_ENDPOINT_MAX);
hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id];
return false;
edpt->next_pid = HCTSIZ_PID_DATA0;
return true;
}
//--------------------------------------------------------------------
@@ -581,24 +599,28 @@ static void handle_rxflvl_irq(uint8_t rhport) {
dfifo_read_packet(dwc2, xfer->buffer, byte_count);
xfer->buffer += byte_count;
const uint16_t remain_bytes = (uint16_t) channel->hctsiz_bm.xfer_size;
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
if (byte_count < channel->hcchar_bm.ep_size) {
// short packet, minus remaining bytes
const uint16_t remain_bytes = (uint16_t) channel->hctsiz_bm.xfer_size;
xfer->total_bytes -= remain_bytes;
// update PID since we got short packet
TU_ASSERT(xfer->ep_id < CFG_TUH_DWC2_ENDPOINT_MAX,);
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id]; // update PID
edpt->next_pid = cal_next_pid(edpt->next_pid, remain_packets);
} else {
// still more packet to send
const uint16_t remain_packets = channel->hctsiz_bm.packet_count;
if (remain_packets) {
// still more packet to send
bool const is_period = edpt_is_periodic(channel->hcchar_bm.ep_type);
channel_send_in_token(dwc2, channel, is_period);
}
}
break;
}
case GRXSTS_PKTSTS_RX_COMPLETE:
// In transfer complete: After this entry is popped from the receive FIFO, dwc2 asserts a Transfer Completed
// In transfer complete: After this entry is popped from the rx FIFO, dwc2 asserts a Transfer Completed
// interrupt --> handle_channel_irq()
break;