summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsakumisu <[email protected]>2025-05-11 22:43:49 +0800
committersakumisu <[email protected]>2025-05-11 22:43:49 +0800
commitdc5e8dc5ed92beb1df4f140fbdf766eaeab7ccf3 (patch)
treedc8f35728ec45ef5bb2d92e2414da9f45701af4a
parent4d3770b5d0ca5291941e95b64b68e804b0265b30 (diff)
feat(port/dwc2/usb_hc_dwc2): support external hs hub with fs/ls device
Signed-off-by: sakumisu <[email protected]>
-rw-r--r--port/dwc2/usb_hc_dwc2.c290
1 files changed, 257 insertions, 33 deletions
diff --git a/port/dwc2/usb_hc_dwc2.c b/port/dwc2/usb_hc_dwc2.c
index 3678b405..437d8c34 100644
--- a/port/dwc2/usb_hc_dwc2.c
+++ b/port/dwc2/usb_hc_dwc2.c
@@ -42,6 +42,11 @@ struct dwc2_chan {
uint8_t chidx;
bool inuse;
bool dir_in;
+ bool do_ssplit;
+ bool do_csplit;
+ uint8_t hub_addr;
+ uint8_t hub_port;
+ uint16_t ssplit_frame;
usb_osal_sem_t waitsem;
struct usbh_urb *urb;
uint32_t iso_frame_idx;
@@ -216,12 +221,6 @@ static inline void dwc2_chan_char_init(struct usbh_bus *bus, uint8_t ch_num, uin
regval |= USB_OTG_HCCHAR_EPDIR;
}
- if ((usbh_get_port_speed(bus, 0) == USB_SPEED_HIGH) && (speed != USB_SPEED_HIGH)) {
- USB_LOG_ERR("Do not support LS/FS device on HS hub\r\n");
- while (1) {
- }
- }
-
/* LS device plugged to HUB */
if ((speed == USB_SPEED_LOW) && (usbh_get_port_speed(bus, 0) != USB_SPEED_LOW)) {
regval |= USB_OTG_HCCHAR_LSDEV;
@@ -234,6 +233,30 @@ static inline void dwc2_chan_char_init(struct usbh_bus *bus, uint8_t ch_num, uin
USB_OTG_HC((uint32_t)ch_num)->HCCHAR = regval;
}
+static inline void dwc2_chan_splt_init(struct usbh_bus *bus, uint8_t ch_num)
+{
+ struct dwc2_chan *chan;
+ uint32_t hcsplt;
+
+ chan = &g_dwc2_hcd[bus->hcd.hcd_id].chan_pool[ch_num];
+
+ if (chan->do_ssplit) {
+ hcsplt = USB_OTG_HCSPLT_SPLITEN;
+ hcsplt |= (chan->hub_addr << USB_OTG_HCSPLT_HUBADDR_Pos);
+ hcsplt |= chan->hub_port;
+
+ if (chan->do_csplit) {
+ hcsplt |= USB_OTG_HCSPLT_COMPLSPLT;
+ } else {
+ hcsplt &= ~USB_OTG_HCSPLT_COMPLSPLT;
+ }
+
+ USB_OTG_HC((uint32_t)ch_num)->HCSPLT = hcsplt;
+ } else {
+ USB_OTG_HC((uint32_t)ch_num)->HCSPLT = 0U;
+ }
+}
+
static void dwc2_chan_init(struct usbh_bus *bus, uint8_t ch_num, uint8_t devaddr, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps, uint8_t speed)
{
uint32_t regval;
@@ -242,18 +265,13 @@ static void dwc2_chan_init(struct usbh_bus *bus, uint8_t ch_num, uint8_t devaddr
USB_OTG_HC((uint32_t)ch_num)->HCINT = 0xFFFFFFFFU;
/* Enable channel interrupts required for this transfer. */
- regval = USB_OTG_HCINTMSK_CHHM;
-
- if (ep_type == USB_ENDPOINT_TYPE_INTERRUPT) {
- regval |= USB_OTG_HCINTMSK_NAKM;
- }
-
- USB_OTG_HC((uint32_t)ch_num)->HCINTMSK = regval;
+ USB_OTG_HC((uint32_t)ch_num)->HCINTMSK = USB_OTG_HCINTMSK_CHHM;
/* Enable the top level host channel interrupt. */
USB_OTG_HOST->HAINTMSK |= 1UL << (ch_num & 0xFU);
dwc2_chan_char_init(bus, ch_num, devaddr, ep_addr, ep_type, ep_mps, speed);
+ dwc2_chan_splt_init(bus, ch_num);
}
/* For IN channel HCTSIZ.XferSize is expected to be an integer multiple of ep_mps size.*/
@@ -352,6 +370,14 @@ static inline uint32_t dwc2_get_glb_intstatus(struct usbh_bus *bus)
return tmpreg;
}
+static inline uint16_t dwc2_get_full_frame_num(struct usbh_bus *bus)
+{
+ uint16_t frame = usbh_get_frame_number(bus);
+
+ /* USB_OTG_HFNUM_FRNUM_Msk is 0xFFFF��but max frame num is 0x3FFF */
+ return ((frame & 0x3FFF) >> 3);
+}
+
static int dwc2_chan_alloc(struct usbh_bus *bus)
{
size_t flags;
@@ -362,6 +388,9 @@ static int dwc2_chan_alloc(struct usbh_bus *bus)
if (!g_dwc2_hcd[bus->hcd.hcd_id].chan_pool[chidx].inuse) {
g_dwc2_hcd[bus->hcd.hcd_id].chan_pool[chidx].inuse = true;
usb_osal_leave_critical_section(flags);
+
+ g_dwc2_hcd[bus->hcd.hcd_id].chan_pool[chidx].do_ssplit = 0;
+ g_dwc2_hcd[bus->hcd.hcd_id].chan_pool[chidx].do_csplit = 0;
return chidx;
}
}
@@ -404,9 +433,29 @@ static uint16_t dwc2_calculate_packet_num(uint32_t input_size, uint8_t ep_addr,
static void dwc2_control_urb_init(struct usbh_bus *bus, uint8_t chidx, struct usbh_urb *urb, struct usb_setup_packet *setup, uint8_t *buffer, uint32_t buflen)
{
struct dwc2_chan *chan;
+ uint32_t datalen;
+ uint8_t data_pid;
chan = &g_dwc2_hcd[bus->hcd.hcd_id].chan_pool[chidx];
+ /* split buflen with ep mps */
+ if (chan->do_ssplit && (chan->ep0_state == DWC2_EP0_STATE_INDATA || chan->ep0_state == DWC2_EP0_STATE_OUTDATA)) {
+ if (buflen > USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) {
+ datalen = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
+ } else {
+ datalen = buflen;
+ }
+
+ if (urb->data_toggle == 0) {
+ data_pid = HC_PID_DATA0;
+ } else {
+ data_pid = HC_PID_DATA1;
+ }
+ } else {
+ datalen = buflen; // buflen = setup->wLength
+ data_pid = HC_PID_DATA1;
+ }
+
if (chan->ep0_state == DWC2_EP0_STATE_SETUP) /* fill setup */
{
chan->num_packets = dwc2_calculate_packet_num(8, 0x00, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
@@ -414,14 +463,14 @@ static void dwc2_control_urb_init(struct usbh_bus *bus, uint8_t chidx, struct us
dwc2_chan_transfer(bus, chidx, 0x00, (uint8_t *)setup, chan->xferlen, chan->num_packets, HC_PID_SETUP);
} else if (chan->ep0_state == DWC2_EP0_STATE_INDATA) /* fill in data */
{
- chan->num_packets = dwc2_calculate_packet_num(setup->wLength, 0x80, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
+ chan->num_packets = dwc2_calculate_packet_num(datalen, 0x80, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
dwc2_chan_init(bus, chidx, urb->hport->dev_addr, 0x80, USB_ENDPOINT_TYPE_CONTROL, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), urb->hport->speed);
- dwc2_chan_transfer(bus, chidx, 0x80, buffer, chan->xferlen, chan->num_packets, HC_PID_DATA1);
+ dwc2_chan_transfer(bus, chidx, 0x80, buffer, chan->xferlen, chan->num_packets, data_pid);
} else if (chan->ep0_state == DWC2_EP0_STATE_OUTDATA) /* fill out data */
{
- chan->num_packets = dwc2_calculate_packet_num(setup->wLength, 0x00, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
+ chan->num_packets = dwc2_calculate_packet_num(datalen, 0x00, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
dwc2_chan_init(bus, chidx, urb->hport->dev_addr, 0x00, USB_ENDPOINT_TYPE_CONTROL, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), urb->hport->speed);
- dwc2_chan_transfer(bus, chidx, 0x00, buffer, chan->xferlen, chan->num_packets, HC_PID_DATA1);
+ dwc2_chan_transfer(bus, chidx, 0x00, buffer, chan->xferlen, chan->num_packets, data_pid);
} else if (chan->ep0_state == DWC2_EP0_STATE_INSTATUS) /* fill in status */
{
chan->num_packets = dwc2_calculate_packet_num(0, 0x80, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
@@ -438,10 +487,21 @@ static void dwc2_control_urb_init(struct usbh_bus *bus, uint8_t chidx, struct us
static void dwc2_bulk_intr_urb_init(struct usbh_bus *bus, uint8_t chidx, struct usbh_urb *urb, uint8_t *buffer, uint32_t buflen)
{
struct dwc2_chan *chan;
+ uint32_t datalen;
chan = &g_dwc2_hcd[bus->hcd.hcd_id].chan_pool[chidx];
- chan->num_packets = dwc2_calculate_packet_num(buflen, urb->ep->bEndpointAddress, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
+ if (chan->do_ssplit) {
+ if (buflen > USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize)) {
+ datalen = USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize);
+ } else {
+ datalen = buflen;
+ }
+ } else {
+ datalen = buflen;
+ }
+
+ chan->num_packets = dwc2_calculate_packet_num(datalen, urb->ep->bEndpointAddress, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), &chan->xferlen);
dwc2_chan_init(bus, chidx, urb->hport->dev_addr, urb->ep->bEndpointAddress, USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes), USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize), urb->hport->speed);
dwc2_chan_transfer(bus, chidx, urb->ep->bEndpointAddress, buffer, chan->xferlen, chan->num_packets, urb->data_toggle == 0 ? HC_PID_DATA0 : HC_PID_DATA1);
}
@@ -802,6 +862,15 @@ int usbh_submit_urb(struct usbh_urb *urb)
chan = &g_dwc2_hcd[bus->hcd.hcd_id].chan_pool[chidx];
chan->chidx = chidx;
chan->urb = urb;
+ chan->do_ssplit = 0;
+
+ if (urb->hport->speed != USB_SPEED_HIGH &&
+ usbh_get_port_speed(bus, 0) == USB_SPEED_HIGH) {
+ chan->do_ssplit = 1;
+ chan->do_csplit = 0;
+ chan->hub_port = urb->hport->port;
+ chan->hub_addr = urb->hport->parent->hub_addr;
+ }
urb->hcpriv = chan;
urb->errorcode = -USB_ERR_BUSY;
@@ -919,6 +988,7 @@ static void dwc2_inchan_irq_handler(struct usbh_bus *bus, uint8_t ch_num)
//uint32_t has_used_packets = chan->num_packets - ((USB_OTG_HC(ch_num)->HCTSIZ & USB_OTG_HCTSIZ_PKTCNT) >> 19); /* how many packets have used */
urb->actual_length += count;
+ urb->transfer_buffer_length -= count;
uint8_t data_toggle = ((USB_OTG_HC(ch_num)->HCTSIZ & USB_OTG_HCTSIZ_DPID) >> USB_OTG_HCTSIZ_DPID_Pos);
@@ -932,17 +1002,27 @@ static void dwc2_inchan_irq_handler(struct usbh_bus *bus, uint8_t ch_num)
usb_dcache_invalidate((uintptr_t)urb->transfer_buffer, USB_ALIGN_UP(count, CONFIG_USB_ALIGN_SIZE));
}
+ chan->do_csplit = 0;
+
if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_CONTROL) {
if (chan->ep0_state == DWC2_EP0_STATE_INDATA) {
- chan->ep0_state = DWC2_EP0_STATE_OUTSTATUS;
- dwc2_control_urb_init(bus, ch_num, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
+ if (chan->do_ssplit && urb->transfer_buffer_length > 0) {
+ dwc2_control_urb_init(bus, ch_num, urb, urb->setup, urb->transfer_buffer + urb->actual_length - 8, urb->transfer_buffer_length);
+ } else {
+ chan->ep0_state = DWC2_EP0_STATE_OUTSTATUS;
+ dwc2_control_urb_init(bus, ch_num, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
+ }
} else if (chan->ep0_state == DWC2_EP0_STATE_INSTATUS) {
chan->ep0_state = DWC2_EP0_STATE_SETUP;
dwc2_urb_waitup(urb);
}
} else if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
} else {
- dwc2_urb_waitup(urb);
+ if (chan->do_ssplit && urb->transfer_buffer_length > 0 && (count == USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize))) {
+ dwc2_bulk_intr_urb_init(bus, ch_num, urb, urb->transfer_buffer + urb->actual_length, urb->transfer_buffer_length);
+ } else {
+ dwc2_urb_waitup(urb);
+ }
}
} else if (chan_intstatus & USB_OTG_HCINT_AHBERR) {
urb->errorcode = -USB_ERR_IO;
@@ -951,11 +1031,74 @@ static void dwc2_inchan_irq_handler(struct usbh_bus *bus, uint8_t ch_num)
urb->errorcode = -USB_ERR_STALL;
dwc2_urb_waitup(urb);
} else if (chan_intstatus & USB_OTG_HCINT_NAK) {
- urb->errorcode = -USB_ERR_NAK;
- dwc2_urb_waitup(urb);
+ if (chan->do_ssplit) {
+ /*
+ * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
+ * interrupt. Re-start the SSPLIT transfer.
+ */
+ switch (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes)) {
+ case USB_ENDPOINT_TYPE_CONTROL:
+ chan->do_csplit = 0;
+ dwc2_control_urb_init(bus, ch_num, urb, urb->setup, urb->transfer_buffer + urb->actual_length - 8, urb->transfer_buffer_length);
+ break;
+ case USB_ENDPOINT_TYPE_BULK:
+ case USB_ENDPOINT_TYPE_INTERRUPT:
+ chan->do_csplit = 0;
+ dwc2_bulk_intr_urb_init(bus, ch_num, urb, urb->transfer_buffer + urb->actual_length, urb->transfer_buffer_length);
+ break;
+ default:
+ break;
+ }
+ } else {
+ urb->errorcode = -USB_ERR_NAK;
+ dwc2_urb_waitup(urb);
+ }
+ } else if (chan_intstatus & USB_OTG_HCINT_ACK) {
+ if (chan->do_ssplit) {
+ /* Handle ACK on SSPLIT. ACK should not occur in CSPLIT. */
+ switch (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes)) {
+ case USB_ENDPOINT_TYPE_CONTROL:
+ chan->do_csplit = 1;
+ dwc2_control_urb_init(bus, ch_num, urb, urb->setup, urb->transfer_buffer + urb->actual_length - 8, urb->transfer_buffer_length);
+ break;
+ case USB_ENDPOINT_TYPE_BULK:
+ case USB_ENDPOINT_TYPE_INTERRUPT:
+ //printf("intr ack, len:%d\r\n", urb->actual_length);
+ chan->do_csplit = 1;
+ chan->ssplit_frame = dwc2_get_full_frame_num(bus);
+ dwc2_bulk_intr_urb_init(bus, ch_num, urb, urb->transfer_buffer + urb->actual_length, urb->transfer_buffer_length);
+ break;
+ default:
+ break;
+ }
+ }
} else if (chan_intstatus & USB_OTG_HCINT_NYET) {
- urb->errorcode = -USB_ERR_NAK;
- dwc2_urb_waitup(urb);
+ if (chan->do_ssplit) {
+ /*
+ * NYET on CSPLIT
+ * re-do the CSPLIT immediately on non-periodic
+ */
+ switch (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes)) {
+ case USB_ENDPOINT_TYPE_CONTROL:
+ chan->do_csplit = 1;
+ dwc2_control_urb_init(bus, ch_num, urb, urb->setup, urb->transfer_buffer + urb->actual_length - 8, urb->transfer_buffer_length);
+ break;
+ case USB_ENDPOINT_TYPE_BULK:
+ case USB_ENDPOINT_TYPE_INTERRUPT:
+ if ((dwc2_get_full_frame_num(bus) - chan->ssplit_frame) > 4) {
+ chan->do_csplit = 0;
+ } else {
+ chan->do_csplit = 1;
+ }
+ dwc2_bulk_intr_urb_init(bus, ch_num, urb, urb->transfer_buffer + urb->actual_length, urb->transfer_buffer_length);
+ break;
+ default:
+ break;
+ }
+ } else {
+ urb->errorcode = -USB_ERR_NAK;
+ dwc2_urb_waitup(urb);
+ }
} else if (chan_intstatus & USB_OTG_HCINT_TXERR) {
urb->errorcode = -USB_ERR_IO;
dwc2_urb_waitup(urb);
@@ -992,7 +1135,16 @@ static void dwc2_outchan_irq_handler(struct usbh_bus *bus, uint8_t ch_num)
uint32_t count = USB_OTG_HC(ch_num)->HCTSIZ & USB_OTG_HCTSIZ_XFRSIZ; /* last packet size */
uint32_t has_used_packets = chan->num_packets - ((USB_OTG_HC(ch_num)->HCTSIZ & USB_OTG_HCTSIZ_PKTCNT) >> 19); /* how many packets have used */
- urb->actual_length += (has_used_packets - 1) * USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize) + count; //the same with urb->actual_length += chan->xferlen;
+ uint32_t olen = (has_used_packets - 1) * USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize) + count; //the same with urb->actual_length += chan->xferlen;
+ urb->actual_length += olen;
+
+ if (chan->ep0_state == DWC2_EP0_STATE_OUTDATA || urb->setup == NULL) {
+ if (urb->transfer_buffer_length > olen) {
+ urb->transfer_buffer_length -= olen;
+ } else {
+ urb->transfer_buffer_length = 0;
+ }
+ }
uint8_t data_toggle = ((USB_OTG_HC(ch_num)->HCTSIZ & USB_OTG_HCTSIZ_DPID) >> USB_OTG_HCTSIZ_DPID_Pos);
@@ -1002,6 +1154,8 @@ static void dwc2_outchan_irq_handler(struct usbh_bus *bus, uint8_t ch_num)
urb->data_toggle = 1;
}
+ chan->do_csplit = 0;
+
if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_CONTROL) {
if (chan->ep0_state == DWC2_EP0_STATE_SETUP) {
if (urb->setup->wLength) {
@@ -1015,15 +1169,23 @@ static void dwc2_outchan_irq_handler(struct usbh_bus *bus, uint8_t ch_num)
}
dwc2_control_urb_init(bus, ch_num, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
} else if (chan->ep0_state == DWC2_EP0_STATE_OUTDATA) {
- chan->ep0_state = DWC2_EP0_STATE_INSTATUS;
- dwc2_control_urb_init(bus, ch_num, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
+ if (chan->do_ssplit && urb->transfer_buffer_length > 0) {
+ dwc2_control_urb_init(bus, ch_num, urb, urb->setup, urb->transfer_buffer + urb->actual_length - 8, urb->transfer_buffer_length);
+ } else {
+ chan->ep0_state = DWC2_EP0_STATE_INSTATUS;
+ dwc2_control_urb_init(bus, ch_num, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
+ }
} else if (chan->ep0_state == DWC2_EP0_STATE_OUTSTATUS) {
chan->ep0_state = DWC2_EP0_STATE_SETUP;
dwc2_urb_waitup(urb);
}
} else if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
} else {
- dwc2_urb_waitup(urb);
+ if (chan->do_ssplit && urb->transfer_buffer_length > 0) {
+ dwc2_control_urb_init(bus, ch_num, urb, urb->setup, urb->transfer_buffer + urb->actual_length - 8, urb->transfer_buffer_length);
+ } else {
+ dwc2_urb_waitup(urb);
+ }
}
} else if (chan_intstatus & USB_OTG_HCINT_AHBERR) {
urb->errorcode = -USB_ERR_IO;
@@ -1032,11 +1194,73 @@ static void dwc2_outchan_irq_handler(struct usbh_bus *bus, uint8_t ch_num)
urb->errorcode = -USB_ERR_STALL;
dwc2_urb_waitup(urb);
} else if (chan_intstatus & USB_OTG_HCINT_NAK) {
- urb->errorcode = -USB_ERR_NAK;
- dwc2_urb_waitup(urb);
+ if (chan->do_ssplit) {
+ /*
+ * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
+ * interrupt. Re-start the SSPLIT transfer.
+ */
+ switch (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes)) {
+ case USB_ENDPOINT_TYPE_CONTROL:
+ chan->do_csplit = 0;
+ dwc2_control_urb_init(bus, ch_num, urb, urb->setup, urb->transfer_buffer + urb->actual_length - 8, urb->transfer_buffer_length);
+ break;
+ case USB_ENDPOINT_TYPE_BULK:
+ case USB_ENDPOINT_TYPE_INTERRUPT:
+ chan->do_csplit = 0;
+ dwc2_bulk_intr_urb_init(bus, ch_num, urb, urb->transfer_buffer + urb->actual_length, urb->transfer_buffer_length);
+ break;
+ default:
+ break;
+ }
+ } else {
+ urb->errorcode = -USB_ERR_NAK;
+ dwc2_urb_waitup(urb);
+ }
+ } else if (chan_intstatus & USB_OTG_HCINT_ACK) {
+ if (chan->do_ssplit) {
+ /* Handle ACK on SSPLIT. ACK should not occur in CSPLIT. */
+ switch (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes)) {
+ case USB_ENDPOINT_TYPE_CONTROL:
+ chan->do_csplit = 1;
+ dwc2_control_urb_init(bus, ch_num, urb, urb->setup, urb->transfer_buffer + urb->actual_length - 8, urb->transfer_buffer_length);
+ break;
+ case USB_ENDPOINT_TYPE_BULK:
+ case USB_ENDPOINT_TYPE_INTERRUPT:
+ chan->do_csplit = 1;
+ chan->ssplit_frame = dwc2_get_full_frame_num(bus);
+ dwc2_bulk_intr_urb_init(bus, ch_num, urb, urb->transfer_buffer + urb->actual_length, urb->transfer_buffer_length);
+ break;
+ default:
+ break;
+ }
+ }
} else if (chan_intstatus & USB_OTG_HCINT_NYET) {
- urb->errorcode = -USB_ERR_NAK;
- dwc2_urb_waitup(urb);
+ if (chan->do_ssplit) {
+ /*
+ * NYET on CSPLIT
+ * re-do the CSPLIT immediately on non-periodic
+ */
+ switch (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes)) {
+ case USB_ENDPOINT_TYPE_CONTROL:
+ chan->do_csplit = 1;
+ dwc2_control_urb_init(bus, ch_num, urb, urb->setup, urb->transfer_buffer + urb->actual_length - 8, urb->transfer_buffer_length);
+ break;
+ case USB_ENDPOINT_TYPE_BULK:
+ case USB_ENDPOINT_TYPE_INTERRUPT:
+ if ((dwc2_get_full_frame_num(bus) - chan->ssplit_frame) > 4) {
+ chan->do_csplit = 0;
+ } else {
+ chan->do_csplit = 1;
+ }
+ dwc2_bulk_intr_urb_init(bus, ch_num, urb, urb->transfer_buffer + urb->actual_length, urb->transfer_buffer_length);
+ break;
+ default:
+ break;
+ }
+ } else {
+ urb->errorcode = -USB_ERR_NAK;
+ dwc2_urb_waitup(urb);
+ }
} else if (chan_intstatus & USB_OTG_HCINT_TXERR) {
urb->errorcode = -USB_ERR_IO;
dwc2_urb_waitup(urb);