diff --git a/drivers/usb/udc/udc_common.c b/drivers/usb/udc/udc_common.c index bef3f657382..b5bae12192f 100644 --- a/drivers/usb/udc/udc_common.c +++ b/drivers/usb/udc/udc_common.c @@ -745,6 +745,7 @@ int udc_enable(const struct device *dev) } data->stage = CTRL_PIPE_STAGE_SETUP; + data->setup = NULL; ret = api->enable(dev); if (ret == 0) { @@ -1011,6 +1012,14 @@ void udc_ctrl_update_stage(const struct device *dev, if (bi->setup && bi->ep == USB_CONTROL_EP_OUT) { uint16_t length = udc_data_stage_length(buf); + if (data->setup) { + /* Host started new control transfer before the previous + * one finished. This was most likely due to a timeout. + * Release old setup buffer as it is no longer needed. + */ + net_buf_unref(data->setup); + } + data->setup = buf; if (data->stage != CTRL_PIPE_STAGE_SETUP) { diff --git a/drivers/usb/udc/udc_dwc2.c b/drivers/usb/udc/udc_dwc2.c index d1fc555d839..d0f77ae0207 100644 --- a/drivers/usb/udc/udc_dwc2.c +++ b/drivers/usb/udc/udc_dwc2.c @@ -139,6 +139,9 @@ struct udc_dwc2_data { uint8_t setup[8]; }; +static void udc_dwc2_ep_disable(const struct device *dev, + struct udc_ep_config *const cfg, bool stall); + #if defined(CONFIG_PINCTRL) #include @@ -801,6 +804,7 @@ static int dwc2_handle_evt_setup(const struct device *dev) buf = udc_buf_get_all(dev, USB_CONTROL_EP_IN); if (buf) { + udc_dwc2_ep_disable(dev, udc_get_ep_cfg(dev, USB_CONTROL_EP_IN), false); net_buf_unref(buf); } @@ -1493,7 +1497,8 @@ static void udc_dwc2_ep_disable(const struct device *dev, dxepctl_reg = dwc2_get_dxepctl_reg(dev, cfg->addr); dxepctl = sys_read32(dxepctl_reg); - if (!is_iso && (dxepctl & USB_DWC2_DEPCTL_NAKSTS)) { + if (!is_iso && (dxepctl & USB_DWC2_DEPCTL_NAKSTS) && + !(dxepctl & USB_DWC2_DEPCTL_EPENA)) { /* Endpoint already sends forced NAKs. STALL if necessary. */ if (stall) { dxepctl |= USB_DWC2_DEPCTL_STALL; diff --git a/subsys/usb/device_next/usbd_ch9.c b/subsys/usb/device_next/usbd_ch9.c index ed7cf14f68d..6d8338f58fb 100644 --- a/subsys/usb/device_next/usbd_ch9.c +++ b/subsys/usb/device_next/usbd_ch9.c @@ -1102,6 +1102,7 @@ int usbd_handle_ctrl_xfer(struct usbd_context *const uds_ctx, buf, bi->ep, buf->len, bi->setup, bi->data, bi->status); if (bi->setup && bi->ep == USB_CONTROL_EP_OUT) { + struct udc_data *data = uds_ctx->dev->data; struct net_buf *next_buf; if (ctrl_xfer_get_setup(uds_ctx, buf)) { @@ -1112,6 +1113,7 @@ int usbd_handle_ctrl_xfer(struct usbd_context *const uds_ctx, /* Remove setup packet buffer from the chain */ next_buf = net_buf_frag_del(NULL, buf); + data->setup = NULL; if (next_buf == NULL) { LOG_ERR("Buffer for data|status is missing"); goto ctrl_xfer_stall;