Skip to content

Commit 0be5b3d

Browse files
committed
pbio/drv/usb/usb_ev3.c: Handle multiple EP0 events at once
There is no guarantee that these events can only happen one at a time. If we happen to miss an event, it may cause the USB control transfer state machine to fall out of sync, which can cause enumeration failures.
1 parent 2b2ae66 commit 0be5b3d

File tree

1 file changed

+157
-152
lines changed

1 file changed

+157
-152
lines changed

lib/pbio/drv/usb/usb_ev3.c

Lines changed: 157 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -515,198 +515,203 @@ static void usb_device_intr(void) {
515515
HWREGH(USB0_BASE + USB_O_CSRL0) = 0;
516516
pbdrv_usb_setup_data_to_send = 0;
517517
pbdrv_usb_addr_needs_setting = false;
518-
} else if (peri_csr & USB_CSRL0_SETEND) {
518+
}
519+
520+
if (peri_csr & USB_CSRL0_SETEND) {
519521
// Error in SETUP transaction
520522
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_SETENDC;
521523
pbdrv_usb_setup_data_to_send = 0;
522524
pbdrv_usb_addr_needs_setting = false;
523-
} else {
524-
if (pbdrv_usb_addr_needs_setting) {
525-
USBDevAddrSet(USB0_BASE, pbdrv_usb_addr);
526-
pbdrv_usb_addr_needs_setting = false;
527-
}
525+
}
528526

529-
if (peri_csr & USB_CSRL0_RXRDY) {
530-
// Got a new setup packet
531-
pbdrv_usb_setup_packet_union_t setup_pkt;
532-
bool handled = false;
533-
pbdrv_usb_setup_data_to_send = 0;
527+
// If we got here (and didn't wipe out this flag),
528+
// then this indicates completion of the SET_ADDRESS command.
529+
// We thus have to make it take effect at this point.
530+
if (pbdrv_usb_addr_needs_setting) {
531+
USBDevAddrSet(USB0_BASE, pbdrv_usb_addr);
532+
pbdrv_usb_addr_needs_setting = false;
533+
}
534534

535-
setup_pkt.u[0] = HWREG(USB0_BASE + USB_O_FIFO0);
536-
setup_pkt.u[1] = HWREG(USB0_BASE + USB_O_FIFO0);
537-
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_RXRDYC;
535+
if (peri_csr & USB_CSRL0_RXRDY) {
536+
// Got a new setup packet
537+
pbdrv_usb_setup_packet_union_t setup_pkt;
538+
bool handled = false;
539+
pbdrv_usb_setup_data_to_send = 0;
538540

539-
switch (setup_pkt.s.bmRequestType & BM_REQ_TYPE_MASK) {
540-
case BM_REQ_TYPE_STANDARD:
541-
switch (setup_pkt.s.bmRequestType & BM_REQ_RECIP_MASK) {
542-
case BM_REQ_RECIP_DEV:
543-
switch (setup_pkt.s.bRequest) {
544-
case SET_ADDRESS:
545-
pbdrv_usb_addr = setup_pkt.s.wValue;
546-
pbdrv_usb_addr_needs_setting = true;
547-
handled = true;
548-
break;
541+
setup_pkt.u[0] = HWREG(USB0_BASE + USB_O_FIFO0);
542+
setup_pkt.u[1] = HWREG(USB0_BASE + USB_O_FIFO0);
543+
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_RXRDYC;
544+
545+
switch (setup_pkt.s.bmRequestType & BM_REQ_TYPE_MASK) {
546+
case BM_REQ_TYPE_STANDARD:
547+
switch (setup_pkt.s.bmRequestType & BM_REQ_RECIP_MASK) {
548+
case BM_REQ_RECIP_DEV:
549+
switch (setup_pkt.s.bRequest) {
550+
case SET_ADDRESS:
551+
pbdrv_usb_addr = setup_pkt.s.wValue;
552+
pbdrv_usb_addr_needs_setting = true;
553+
handled = true;
554+
break;
549555

550-
case SET_CONFIGURATION:
551-
if (setup_pkt.s.wValue <= 1) {
552-
pbdrv_usb_config = setup_pkt.s.wValue;
556+
case SET_CONFIGURATION:
557+
if (setup_pkt.s.wValue <= 1) {
558+
pbdrv_usb_config = setup_pkt.s.wValue;
553559

554-
if (pbdrv_usb_config == 1) {
555-
// configuring
560+
if (pbdrv_usb_config == 1) {
561+
// configuring
556562

557-
// Reset data toggle, clear stall, flush fifo
558-
HWREGB(USB0_BASE + USB_O_TXCSRL1) = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
559-
HWREGB(USB0_BASE + USB_O_RXCSRL1) = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
560-
} else {
561-
// deconfiguring
563+
// Reset data toggle, clear stall, flush fifo
564+
HWREGB(USB0_BASE + USB_O_TXCSRL1) = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
565+
HWREGB(USB0_BASE + USB_O_RXCSRL1) = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
566+
} else {
567+
// deconfiguring
562568

563-
// Set stall condition
564-
HWREGB(USB0_BASE + USB_O_TXCSRL1) = USB_TXCSRL1_STALL;
565-
HWREGB(USB0_BASE + USB_O_RXCSRL1) = USB_RXCSRL1_STALL;
566-
}
567-
handled = true;
569+
// Set stall condition
570+
HWREGB(USB0_BASE + USB_O_TXCSRL1) = USB_TXCSRL1_STALL;
571+
HWREGB(USB0_BASE + USB_O_RXCSRL1) = USB_RXCSRL1_STALL;
568572
}
569-
break;
573+
handled = true;
574+
}
575+
break;
570576

571-
case GET_CONFIGURATION:
572-
pbdrv_usb_setup_misc_tx_byte = pbdrv_usb_config;
577+
case GET_CONFIGURATION:
578+
pbdrv_usb_setup_misc_tx_byte = pbdrv_usb_config;
579+
pbdrv_usb_setup_data_to_send = &pbdrv_usb_setup_misc_tx_byte;
580+
pbdrv_usb_setup_data_to_send_sz = 1;
581+
handled = true;
582+
break;
583+
584+
case GET_STATUS:
585+
pbdrv_usb_setup_misc_tx_byte = 1; // self-powered
586+
pbdrv_usb_setup_data_to_send = &pbdrv_usb_setup_misc_tx_byte;
587+
pbdrv_usb_setup_data_to_send_sz = 2;
588+
handled = true;
589+
break;
590+
591+
case GET_DESCRIPTOR:
592+
if (usb_get_descriptor(setup_pkt.s.wValue)) {
593+
handled = true;
594+
}
595+
break;
596+
}
597+
break;
598+
599+
case BM_REQ_RECIP_IF:
600+
if (setup_pkt.s.wIndex == 0) {
601+
switch (setup_pkt.s.bRequest) {
602+
case GET_INTERFACE:
603+
pbdrv_usb_setup_misc_tx_byte = 0;
573604
pbdrv_usb_setup_data_to_send = &pbdrv_usb_setup_misc_tx_byte;
574605
pbdrv_usb_setup_data_to_send_sz = 1;
575606
handled = true;
576607
break;
577608

578609
case GET_STATUS:
579-
pbdrv_usb_setup_misc_tx_byte = 1; // self-powered
610+
pbdrv_usb_setup_misc_tx_byte = 0;
580611
pbdrv_usb_setup_data_to_send = &pbdrv_usb_setup_misc_tx_byte;
581612
pbdrv_usb_setup_data_to_send_sz = 2;
582613
handled = true;
583614
break;
584-
585-
case GET_DESCRIPTOR:
586-
if (usb_get_descriptor(setup_pkt.s.wValue)) {
587-
handled = true;
588-
}
589-
break;
590615
}
591-
break;
592-
593-
case BM_REQ_RECIP_IF:
594-
if (setup_pkt.s.wIndex == 0) {
595-
switch (setup_pkt.s.bRequest) {
596-
case GET_INTERFACE:
597-
pbdrv_usb_setup_misc_tx_byte = 0;
598-
pbdrv_usb_setup_data_to_send = &pbdrv_usb_setup_misc_tx_byte;
599-
pbdrv_usb_setup_data_to_send_sz = 1;
600-
handled = true;
601-
break;
602-
603-
case GET_STATUS:
604-
pbdrv_usb_setup_misc_tx_byte = 0;
605-
pbdrv_usb_setup_data_to_send = &pbdrv_usb_setup_misc_tx_byte;
606-
pbdrv_usb_setup_data_to_send_sz = 2;
607-
handled = true;
608-
break;
616+
}
617+
break;
618+
619+
case BM_REQ_RECIP_EP:
620+
switch (setup_pkt.s.bRequest) {
621+
case GET_STATUS:
622+
if (setup_pkt.s.wIndex == 1) {
623+
pbdrv_usb_setup_misc_tx_byte = !!(HWREGB(USB0_BASE + USB_O_RXCSRL1) & USB_RXCSRL1_STALL);
624+
pbdrv_usb_setup_data_to_send = &pbdrv_usb_setup_misc_tx_byte;
625+
pbdrv_usb_setup_data_to_send_sz = 2;
626+
handled = true;
627+
} else if (setup_pkt.s.wIndex == 0x81) {
628+
pbdrv_usb_setup_misc_tx_byte = !!(HWREGB(USB0_BASE + USB_O_TXCSRL1) & USB_TXCSRL1_STALL);
629+
pbdrv_usb_setup_data_to_send = &pbdrv_usb_setup_misc_tx_byte;
630+
pbdrv_usb_setup_data_to_send_sz = 2;
631+
handled = true;
609632
}
610-
}
611-
break;
633+
break;
612634

613-
case BM_REQ_RECIP_EP:
614-
switch (setup_pkt.s.bRequest) {
615-
case GET_STATUS:
635+
case CLEAR_FEATURE:
636+
if (setup_pkt.s.wValue == 0) {
616637
if (setup_pkt.s.wIndex == 1) {
617-
pbdrv_usb_setup_misc_tx_byte = !!(HWREGB(USB0_BASE + USB_O_RXCSRL1) & USB_RXCSRL1_STALL);
618-
pbdrv_usb_setup_data_to_send = &pbdrv_usb_setup_misc_tx_byte;
619-
pbdrv_usb_setup_data_to_send_sz = 2;
638+
HWREGB(USB0_BASE + USB_O_RXCSRL1) &= ~USB_RXCSRL1_STALL;
620639
handled = true;
621640
} else if (setup_pkt.s.wIndex == 0x81) {
622-
pbdrv_usb_setup_misc_tx_byte = !!(HWREGB(USB0_BASE + USB_O_TXCSRL1) & USB_TXCSRL1_STALL);
623-
pbdrv_usb_setup_data_to_send = &pbdrv_usb_setup_misc_tx_byte;
624-
pbdrv_usb_setup_data_to_send_sz = 2;
641+
HWREGB(USB0_BASE + USB_O_TXCSRL1) &= ~USB_TXCSRL1_STALL;
625642
handled = true;
626643
}
627-
break;
628-
629-
case CLEAR_FEATURE:
630-
if (setup_pkt.s.wValue == 0) {
631-
if (setup_pkt.s.wIndex == 1) {
632-
HWREGB(USB0_BASE + USB_O_RXCSRL1) &= ~USB_RXCSRL1_STALL;
633-
handled = true;
634-
} else if (setup_pkt.s.wIndex == 0x81) {
635-
HWREGB(USB0_BASE + USB_O_TXCSRL1) &= ~USB_TXCSRL1_STALL;
636-
handled = true;
637-
}
638-
}
639-
break;
644+
}
645+
break;
640646

641-
case SET_FEATURE:
642-
if (setup_pkt.s.wValue == 0) {
643-
if (setup_pkt.s.wIndex == 1) {
644-
HWREGB(USB0_BASE + USB_O_RXCSRL1) |= USB_RXCSRL1_STALL;
645-
handled = true;
646-
} else if (setup_pkt.s.wIndex == 0x81) {
647-
HWREGB(USB0_BASE + USB_O_TXCSRL1) |= USB_TXCSRL1_STALL;
648-
handled = true;
649-
}
647+
case SET_FEATURE:
648+
if (setup_pkt.s.wValue == 0) {
649+
if (setup_pkt.s.wIndex == 1) {
650+
HWREGB(USB0_BASE + USB_O_RXCSRL1) |= USB_RXCSRL1_STALL;
651+
handled = true;
652+
} else if (setup_pkt.s.wIndex == 0x81) {
653+
HWREGB(USB0_BASE + USB_O_TXCSRL1) |= USB_TXCSRL1_STALL;
654+
handled = true;
650655
}
651-
break;
652-
}
653-
break;
654-
}
655-
break;
656-
657-
case BM_REQ_TYPE_VENDOR:
658-
switch (setup_pkt.s.bRequest) {
659-
case PBDRV_USB_VENDOR_REQ_WEBUSB:
660-
if (setup_pkt.s.wIndex == WEBUSB_REQ_GET_URL && setup_pkt.s.wValue == PBDRV_USB_WEBUSB_LANDING_PAGE_URL_IDX) {
661-
pbdrv_usb_setup_data_to_send = pbdrv_usb_webusb_landing_page.u;
662-
pbdrv_usb_setup_data_to_send_sz = pbdrv_usb_webusb_landing_page.s.bLength;
663-
handled = true;
664-
}
665-
break;
656+
}
657+
break;
658+
}
659+
break;
660+
}
661+
break;
662+
663+
case BM_REQ_TYPE_VENDOR:
664+
switch (setup_pkt.s.bRequest) {
665+
case PBDRV_USB_VENDOR_REQ_WEBUSB:
666+
if (setup_pkt.s.wIndex == WEBUSB_REQ_GET_URL && setup_pkt.s.wValue == PBDRV_USB_WEBUSB_LANDING_PAGE_URL_IDX) {
667+
pbdrv_usb_setup_data_to_send = pbdrv_usb_webusb_landing_page.u;
668+
pbdrv_usb_setup_data_to_send_sz = pbdrv_usb_webusb_landing_page.s.bLength;
669+
handled = true;
670+
}
671+
break;
672+
673+
case PBDRV_USB_VENDOR_REQ_MS_20:
674+
if (setup_pkt.s.wIndex == MS_OS_20_DESCRIPTOR_INDEX) {
675+
pbdrv_usb_setup_data_to_send = pbdrv_usb_ms_20_desc_set.u;
676+
pbdrv_usb_setup_data_to_send_sz = sizeof(pbdrv_usb_ms_20_desc_set.s);
677+
handled = true;
678+
}
679+
break;
680+
}
681+
}
666682

667-
case PBDRV_USB_VENDOR_REQ_MS_20:
668-
if (setup_pkt.s.wIndex == MS_OS_20_DESCRIPTOR_INDEX) {
669-
pbdrv_usb_setup_data_to_send = pbdrv_usb_ms_20_desc_set.u;
670-
pbdrv_usb_setup_data_to_send_sz = sizeof(pbdrv_usb_ms_20_desc_set.s);
671-
handled = true;
672-
}
673-
break;
674-
}
675-
}
683+
if (!handled) {
684+
// send stall
685+
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_STALL;
686+
} else {
687+
if (pbdrv_usb_setup_data_to_send) {
688+
// Clamp by host request size
689+
if (setup_pkt.s.wLength < pbdrv_usb_setup_data_to_send_sz) {
690+
pbdrv_usb_setup_data_to_send_sz = setup_pkt.s.wLength;
691+
}
676692

677-
if (!handled) {
678-
// send stall
679-
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_STALL;
680-
} else {
681-
if (pbdrv_usb_setup_data_to_send) {
682-
// Clamp by host request size
683-
if (setup_pkt.s.wLength < pbdrv_usb_setup_data_to_send_sz) {
684-
pbdrv_usb_setup_data_to_send_sz = setup_pkt.s.wLength;
685-
}
686-
687-
// Send as much as we can in one chunk
688-
usb_setup_send_chunk();
689-
if (pbdrv_usb_setup_data_to_send_sz == 0) {
690-
pbdrv_usb_setup_data_to_send = 0;
691-
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_TXRDY | USB_CSRL0_DATAEND;
692-
} else {
693-
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_TXRDY;
694-
}
693+
// Send as much as we can in one chunk
694+
usb_setup_send_chunk();
695+
if (pbdrv_usb_setup_data_to_send_sz == 0) {
696+
pbdrv_usb_setup_data_to_send = 0;
697+
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_TXRDY | USB_CSRL0_DATAEND;
695698
} else {
696-
// Just get ready to send ACK, no data
697-
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_DATAEND;
699+
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_TXRDY;
698700
}
699-
}
700-
} else if (pbdrv_usb_setup_data_to_send) {
701-
// Need to continue to TX data
702-
usb_setup_send_chunk();
703-
if (pbdrv_usb_setup_data_to_send_sz == 0) {
704-
pbdrv_usb_setup_data_to_send = 0;
705-
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_TXRDY | USB_CSRL0_DATAEND;
706701
} else {
707-
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_TXRDY;
702+
// Just get ready to send ACK, no data
703+
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_DATAEND;
708704
}
709705
}
706+
} else if (pbdrv_usb_setup_data_to_send) {
707+
// Need to continue to TX data
708+
usb_setup_send_chunk();
709+
if (pbdrv_usb_setup_data_to_send_sz == 0) {
710+
pbdrv_usb_setup_data_to_send = 0;
711+
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_TXRDY | USB_CSRL0_DATAEND;
712+
} else {
713+
HWREGH(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_TXRDY;
714+
}
710715
}
711716
}
712717

0 commit comments

Comments
 (0)