@@ -70,7 +70,8 @@ static struct k_thread drv_stack_data;
7070
7171static struct udc_ep_config ep_cfg_out [CFG_EPOUT_CNT + CFG_EP_ISOOUT_CNT + 1 ];
7272static struct udc_ep_config ep_cfg_in [CFG_EPIN_CNT + CFG_EP_ISOIN_CNT + 1 ];
73- static bool udc_nrf_setup_rcvd ;
73+ static bool udc_nrf_setup_rcvd , udc_nrf_setup_set_addr , udc_nrf_fake_setup ;
74+ static uint8_t udc_nrf_address ;
7475const static struct device * udc_nrf_dev ;
7576
7677struct udc_nrf_config {
@@ -143,7 +144,9 @@ static void udc_event_xfer_ctrl_in(const struct device *dev,
143144 /* Update to next stage of control transfer */
144145 udc_ctrl_update_stage (dev , buf );
145146
146- nrf_usbd_common_setup_clear ();
147+ if (!udc_nrf_setup_set_addr ) {
148+ nrf_usbd_common_setup_clear ();
149+ }
147150}
148151
149152static void udc_event_fake_status_in (const struct device * dev )
@@ -317,6 +320,7 @@ static int usbd_ctrl_feed_dout(const struct device *dev,
317320
318321static int udc_event_xfer_setup (const struct device * dev )
319322{
323+ nrf_usbd_common_setup_t * setup ;
320324 struct net_buf * buf ;
321325 int err ;
322326
@@ -328,7 +332,77 @@ static int udc_event_xfer_setup(const struct device *dev)
328332 }
329333
330334 udc_ep_buf_set_setup (buf );
331- nrf_usbd_common_setup_get ((nrf_usbd_common_setup_t * )buf -> data );
335+ setup = (nrf_usbd_common_setup_t * )buf -> data ;
336+ nrf_usbd_common_setup_get (setup );
337+
338+ /* USBD peripheral automatically handles Set Address in slightly
339+ * different manner than the USB stack.
340+ *
341+ * USBD peripheral doesn't care about wLength, but the peripheral
342+ * switches to new address only after status stage. The device won't
343+ * automatically accept Data Stage packets.
344+ *
345+ * However, in the case the host:
346+ * * sends SETUP Set Address with non-zero wLength
347+ * * does not send corresponding OUT DATA packets (to match wLength)
348+ * or sends the packets but disregards NAK
349+ * or sends the packets that device ACKs
350+ * * sends IN token (either incorrectly proceeds to status stage, or
351+ * manages to send IN before SW sets STALL)
352+ * then the USBD peripheral will accept the address and USB stack won't.
353+ * This will lead to state mismatch between the stack and peripheral.
354+ *
355+ * In cases where the USB stack would like to STALL the request there is
356+ * a race condition between host issuing Set Address status stage (IN
357+ * token) and SW setting STALL bit. If host wins the race, the device
358+ * ACKs status stage and use new address. If device wins the race, the
359+ * device STALLs status stage and address remains unchanged.
360+ */
361+ udc_nrf_setup_set_addr =
362+ setup -> bmRequestType == 0 &&
363+ setup -> bRequest == USB_SREQ_SET_ADDRESS ;
364+ if (udc_nrf_setup_set_addr ) {
365+ if (setup -> wLength ) {
366+ /* Currently USB stack only STALLs OUT Data Stage when
367+ * buffer allocation fails. To prevent the device from
368+ * ACKing the Data Stage, simply ignore the request
369+ * completely.
370+ *
371+ * If host incorrectly proceeds to status stage there
372+ * will be address mismatch (unless the new address is
373+ * equal to current device address). If host does not
374+ * issue IN token then the mismatch will be avoided.
375+ */
376+ net_buf_unref (buf );
377+ return 0 ;
378+ }
379+
380+ /* nRF52/nRF53 USBD doesn't care about wValue bits 8..15 and
381+ * wIndex value but USB device stack does.
382+ *
383+ * Just clear the bits so stack will handle the request in the
384+ * same way as USBD peripheral does, avoiding the mismatch.
385+ */
386+ setup -> wValue &= 0x7F ;
387+ setup -> wIndex = 0 ;
388+ }
389+
390+ if (!udc_nrf_setup_set_addr && udc_nrf_address != NRF_USBD -> USBADDR ) {
391+ /* Address mismatch detected. Fake Set Address handling to
392+ * correct the situation, then repeat handling.
393+ */
394+ udc_nrf_fake_setup = true;
395+ udc_nrf_setup_set_addr = true;
396+
397+ setup -> bmRequestType = 0 ;
398+ setup -> bRequest = USB_SREQ_SET_ADDRESS ;
399+ setup -> wValue = NRF_USBD -> USBADDR ;
400+ setup -> wIndex = 0 ;
401+ setup -> wLength = 0 ;
402+ } else {
403+ udc_nrf_fake_setup = false;
404+ }
405+
332406 net_buf_add (buf , sizeof (nrf_usbd_common_setup_t ));
333407 udc_nrf_setup_rcvd = true;
334408
@@ -487,17 +561,21 @@ static void udc_nrf_power_handler(nrfx_power_usb_evt_t pwr_evt)
487561 }
488562}
489563
490- static void udc_nrf_fake_status_in (const struct device * dev )
564+ static bool udc_nrf_fake_status_in (const struct device * dev )
491565{
492566 struct udc_nrf_evt evt = {
493567 .type = UDC_NRF_EVT_STATUS_IN ,
494568 .ep = USB_CONTROL_EP_IN ,
495569 };
496570
497- if (nrf_usbd_common_last_setup_dir_get () == USB_CONTROL_EP_OUT ) {
571+ if (nrf_usbd_common_last_setup_dir_get () == USB_CONTROL_EP_OUT ||
572+ udc_nrf_fake_setup ) {
498573 /* Let controller perform status IN stage */
499574 k_msgq_put (& drv_msgq , & evt , K_NO_WAIT );
575+ return true;
500576 }
577+
578+ return false;
501579}
502580
503581static int udc_nrf_ep_enqueue (const struct device * dev ,
@@ -512,8 +590,9 @@ static int udc_nrf_ep_enqueue(const struct device *dev,
512590 udc_buf_put (cfg , buf );
513591
514592 if (cfg -> addr == USB_CONTROL_EP_IN && buf -> len == 0 ) {
515- udc_nrf_fake_status_in (dev );
516- return 0 ;
593+ if (udc_nrf_fake_status_in (dev )) {
594+ return 0 ;
595+ }
517596 }
518597
519598 k_msgq_put (& drv_msgq , & evt , K_NO_WAIT );
@@ -608,12 +687,38 @@ static int udc_nrf_ep_clear_halt(const struct device *dev,
608687
609688static int udc_nrf_set_address (const struct device * dev , const uint8_t addr )
610689{
611- /**
612- * Nothing to do here. The USBD HW already takes care of initiating
613- * STATUS stage. Just double check the address for sanity.
690+ /*
691+ * If the status stage already finished (which depends entirely on when
692+ * the host sends IN token) then NRF_USBD->USBADDR will have the same
693+ * address, otherwise it won't (unless new address is unchanged).
694+ *
695+ * Store the address so the driver can detect address mismatches
696+ * between USB stack and USBD peripheral. The mismatches can occur if:
697+ * * SW has high enough latency in SETUP handling, or
698+ * * Host did not issue Status Stage after Set Address request
699+ *
700+ * The SETUP handling latency is a problem because the Set Address is
701+ * automatically handled by device. Because whole Set Address handling
702+ * can finish in less than 21 us, the latency required (with perfect
703+ * timing) to hit the issue is relatively short (2 ms Set Address
704+ * recovery interval + negligible Set Address handling time). If host
705+ * sends new SETUP before SW had a chance to read the Set Address one,
706+ * the Set Address one will be overwritten without a trace.
614707 */
615- if (addr != (uint8_t )NRF_USBD -> USBADDR ) {
616- LOG_WRN ("USB Address incorrect 0x%02x" , addr );
708+ udc_nrf_address = addr ;
709+
710+ if (udc_nrf_fake_setup ) {
711+ struct udc_nrf_evt evt = {
712+ .type = UDC_NRF_EVT_HAL ,
713+ .hal_evt = {
714+ .type = NRF_USBD_COMMON_EVT_SETUP ,
715+ },
716+ };
717+
718+ /* Finished handling lost Set Address, now handle the pending
719+ * SETUP transfer.
720+ */
721+ k_msgq_put (& drv_msgq , & evt , K_NO_WAIT );
617722 }
618723
619724 return 0 ;
0 commit comments