Skip to content

Commit 68b57ea

Browse files
committed
drivers: usb: stm32: Fix data out on control ep
The Linux Compliance tests that are available in the tools/usb folder can be used to validate a usb stack implementation. When ran those tests in the current stm32 boards using the testusb sample next it is possible to see that tests 14 and 21 are failing. Those tests check corner cases when data is expected to be transfered in the control endpoint. This add the missing piece to allow all tests pass when using the devices in Full Speed. When enabling High Speed the test 13 starts to failing. The test 13 is about set/clear the halt endpoint. Fixes #93924 Signed-off-by: BUDKE Gerson Fernando <gerson.budke@leica-geosystems.com>
1 parent e032829 commit 68b57ea

File tree

1 file changed

+66
-7
lines changed

1 file changed

+66
-7
lines changed

drivers/usb/udc/udc_stm32.c

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -322,15 +322,15 @@ static void handle_msg_data_out(struct udc_stm32_data *priv, uint8_t epnum, uint
322322
LOG_DBG("DataOut ep 0x%02x", ep);
323323

324324
epcfg = udc_get_ep_cfg(dev, ep);
325-
udc_ep_set_busy(epcfg, false);
326-
327325
buf = udc_buf_get(epcfg);
328326
if (unlikely(buf == NULL)) {
327+
udc_ep_set_busy(epcfg, false);
329328
LOG_ERR("ep 0x%02x queue is empty", ep);
330329
return;
331330
}
332331

333332
net_buf_add(buf, rx_count);
333+
udc_ep_set_busy(epcfg, false);
334334

335335
if (ep == USB_CONTROL_EP_OUT) {
336336
if (udc_ctrl_stage_is_status_out(dev)) {
@@ -353,6 +353,40 @@ static void handle_msg_data_out(struct udc_stm32_data *priv, uint8_t epnum, uint
353353
}
354354
}
355355

356+
static void handle_msg_data_ep0_out(struct udc_stm32_data *priv, uint8_t epnum, uint16_t rx_count)
357+
{
358+
const struct device *dev = priv->dev;
359+
struct udc_ep_config *epcfg;
360+
uint8_t ep = epnum | USB_EP_DIR_OUT;
361+
struct net_buf *buf;
362+
uint8_t *data;
363+
uint32_t len;
364+
365+
epcfg = udc_get_ep_cfg(dev, ep);
366+
buf = udc_buf_peek(epcfg);
367+
if (unlikely(buf == NULL)) {
368+
udc_ep_set_busy(epcfg, false);
369+
return;
370+
}
371+
372+
len = net_buf_tailroom(buf);
373+
374+
/* Check if all data was transferred and then go back to normal flow
375+
* otherwise continue receiving data
376+
*/
377+
LOG_DBG("xfer size: %d, free: %d, size: %d", rx_count, len, buf->size);
378+
if (len == rx_count || rx_count < epcfg->mps) {
379+
/* busy will be release in handle_msg_data_out() */
380+
handle_msg_data_out(priv, epnum, rx_count);
381+
return;
382+
}
383+
384+
net_buf_add(buf, rx_count);
385+
data = net_buf_tail(buf);
386+
387+
HAL_PCD_EP_Receive(&priv->pcd, epcfg->addr, data, buf->size);
388+
}
389+
356390
static void handle_msg_data_in(struct udc_stm32_data *priv, uint8_t epnum)
357391
{
358392
const struct device *dev = priv->dev;
@@ -363,13 +397,14 @@ static void handle_msg_data_in(struct udc_stm32_data *priv, uint8_t epnum)
363397
LOG_DBG("DataIn ep 0x%02x", ep);
364398

365399
epcfg = udc_get_ep_cfg(dev, ep);
366-
udc_ep_set_busy(epcfg, false);
367-
368400
buf = udc_buf_peek(epcfg);
369401
if (unlikely(buf == NULL)) {
402+
udc_ep_set_busy(epcfg, false);
370403
return;
371404
}
372405

406+
udc_ep_set_busy(epcfg, false);
407+
373408
if (ep == USB_CONTROL_EP_IN && buf->len) {
374409
const struct udc_stm32_config *cfg = dev->config;
375410
uint32_t len = MIN(cfg->ep0_mps, buf->len);
@@ -420,22 +455,38 @@ static void handle_msg_data_in(struct udc_stm32_data *priv, uint8_t epnum)
420455
}
421456
}
422457

458+
static void drop_control_transfers(const struct device *dev)
459+
{
460+
struct net_buf *buf;
461+
462+
buf = udc_buf_get_all(udc_get_ep_cfg(dev, USB_CONTROL_EP_OUT));
463+
if (buf != NULL) {
464+
net_buf_unref(buf);
465+
}
466+
467+
buf = udc_buf_get_all(udc_get_ep_cfg(dev, USB_CONTROL_EP_IN));
468+
if (buf != NULL) {
469+
net_buf_unref(buf);
470+
}
471+
}
472+
423473
static void handle_msg_setup(struct udc_stm32_data *priv)
424474
{
425475
struct usb_setup_packet *setup = (void *)priv->pcd.Setup;
426476
const struct device *dev = priv->dev;
427477
struct net_buf *buf;
428478
int err;
429479

480+
drop_control_transfers(dev);
481+
430482
buf = udc_ctrl_alloc(dev, USB_CONTROL_EP_OUT, sizeof(struct usb_setup_packet));
431483
if (buf == NULL) {
432484
LOG_ERR("Failed to allocate for setup");
433485
return;
434486
}
435487

488+
net_buf_add_mem(buf, setup, sizeof(struct usb_setup_packet));
436489
udc_ep_buf_set_setup(buf);
437-
memcpy(buf->data, setup, 8);
438-
net_buf_add(buf, 8);
439490

440491
udc_ctrl_update_stage(dev, buf);
441492

@@ -450,13 +501,16 @@ static void handle_msg_setup(struct udc_stm32_data *priv)
450501

451502
if (udc_ctrl_stage_is_data_out(dev)) {
452503
/* Allocate and feed buffer for data OUT stage */
504+
LOG_DBG("s:%p|feed for -out-", (void *)buf);
453505
err = usbd_ctrl_feed_dout(dev, udc_data_stage_length(buf));
454506
if (err == -ENOMEM) {
455507
udc_submit_ep_event(dev, buf, err);
456508
}
457509
} else if (udc_ctrl_stage_is_data_in(dev)) {
510+
LOG_DBG("s:%p|feed for -in-status", (void *)buf);
458511
udc_ctrl_submit_s_in_status(dev);
459512
} else {
513+
LOG_DBG("s:%p|no data", (void *)buf);
460514
udc_ctrl_submit_s_status(dev);
461515
}
462516
}
@@ -477,7 +531,12 @@ static void udc_stm32_thread_handler(void *arg1, void *arg2, void *arg3)
477531
handle_msg_data_in(priv, msg.ep);
478532
break;
479533
case UDC_STM32_MSG_DATA_OUT:
480-
handle_msg_data_out(priv, msg.ep, msg.rx_count);
534+
/* workaround to xfer data stage on ep0 */
535+
if (msg.ep == USB_CONTROL_EP_OUT) {
536+
handle_msg_data_ep0_out(priv, msg.ep, msg.rx_count);
537+
} else {
538+
handle_msg_data_out(priv, msg.ep, msg.rx_count);
539+
}
481540
break;
482541
}
483542
}

0 commit comments

Comments
 (0)