[PATCH] media: s2255: cancel the in-flight firmware URB before reloading

From: YuanZhe Liu

Date: Thu Oct 29 2026 - 06:21:36 EST


The driver uses a single URB to upload the firmware. s2255_timer() submits
it one second after s2255_fwload_start() filled in the first chunk, and
s2255_fwchunk_complete() resubmits it for each following chunk.

When the transfer does not complete within S2255_LOAD_TIMEOUT, s2255_open()
stops waiting, sets the firmware state to S2255_FW_FAILED and returns
-EAGAIN. The next open() calls s2255_fwload_start() again, which refills
the URB and arms the timer while the previous transfer may still be owned
by the USB core.

One second later s2255_timer() submits that URB again:

URB 00000000b9ed398a submitted while active
WARNING: drivers/usb/core/urb.c:379 at usb_submit_urb

usb_submit_urb() returns -EBUSY, the firmware state is set to
S2255_FW_FAILED and the device stays unusable. Rewriting the fields of a
URB that is still in flight is unsafe as well.

Cancel the outstanding transfer and the pending timer before reusing the
URB. A killed transfer completes with -ENOENT, so do not report it as a
transfer error.

Fixes: 38f993ad8b1f ("V4L/DVB (8125): This driver adds support for the Sensoray 2255 devices.")
Cc: stable@xxxxxxxxxxxxxxx
Co-developed-by: Bin Yu <byu@xxxxxxxxxxxxx>
Signed-off-by: Bin Yu <byu@xxxxxxxxxxxxx>
Co-developed-by: Cheng Wen <wencheng@xxxxxxxxxxxxx>
Signed-off-by: Cheng Wen <wencheng@xxxxxxxxxxxxx>
Signed-off-by: YuanZhe Liu <25031212351@xxxxxxxxxxxxxxxxx>
---
drivers/media/usb/s2255/s2255drv.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index 15012d73975c..4d5de6930542 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -490,7 +490,9 @@ static void s2255_fwchunk_complete(struct urb *urb)
int len;

if (urb->status) {
- dev_err(&udev->dev, "URB failed with status %d\n", urb->status);
+ if (urb->status != -ENOENT)
+ dev_err(&udev->dev, "URB failed with status %d\n",
+ urb->status);
atomic_set(&data->fw_state, S2255_FW_FAILED);
/* wake up anything waiting for the firmware */
wake_up(&data->wait_fw);
@@ -2187,6 +2189,14 @@ static void s2255_stop_readpipe(struct s2255_dev *dev)

static void s2255_fwload_start(struct s2255_dev *dev)
{
+ /*
+ * A previous load attempt may still have a transfer in flight, e.g.
+ * when s2255_open() timed out and the next open() restarts the load.
+ * Cancel it before rewriting the shared URB.
+ */
+ timer_delete_sync(&dev->timer);
+ usb_kill_urb(dev->fw_data->fw_urb);
+
s2255_reset_dsppower(dev);
dev->fw_data->fw_size = dev->fw_data->fw->size;
atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED);
--
2.34.1