Re: [PATCH v5 2/3] media: uvcvideo: add UVC_QUIRK_CTRL_THROTTLE for fragile firmware

Michal Pecio
2026-04-27T06:36:01Z

[-- Attachment #1: Type: text/plain, Size: 1189 bytes --]

On Mon, 13 Apr 2026 10:05:45 +0200, Michal Pecio wrote:
> Question: can you kill it by starting some video application to set
> the camera up, closing it and then running this loop?
>
> while :; do v4l2-ctl -d /dev/video0 --stream-mmap --stream-count=1; done

Hi again,

Any chance you could try it? And also the attached test program:

cc -lusb-1.0 hammerint.c -o hammerint
sudo ./hammerint 1532 0e05 0 85

Initial arguments are VID:PID of the device, next is the number of
an interface containing some interrupt endpoint and then the endpoint
address (including 8_ if IN).

I tried with a variety of SuperSpeed devices (UVC, NICs, hubs) and this
reliably breaks ASMedia HCs within seconds. If the same is the case on
Intel then it's a bigger problem than just UVC.

The video streaming loop breaks even more controllers. I have some
general idea how the streaming case could be dealt with, but not so
much the interrupt one. Maybe rate limiting. I found that avoiding
Set TR Dequeue to Link TRBs reduces failure rate, but not to zero.

Long ago I also looked at the issued command sequences and I haven't
noticed obvious errors or spec violations. Looks like a HW bug.

Regards,
Michal

[-- Attachment #2: hammerint.c --]
[-- Type: text/x-c++src, Size: 1425 bytes --]

#include <stdio.h>
#include <stdlib.h>

#include <libusb-1.0/libusb.h>

void comp(struct libusb_transfer *t) {
char c = t->status == LIBUSB_TRANSFER_CANCELLED ? '.' :
t->status == LIBUSB_TRANSFER_COMPLETED ? ',' : '-';
fputc(c, stdout);
fflush(stdout);
}

int hammer(int vid, int pid, int ifc, int ep) {
struct libusb_device_handle *d;
struct libusb_transfer *t;
char bufi[1024] = {0};
char bufc[2];
int r;

r = libusb_init(NULL);
t = libusb_alloc_transfer(0);
if (r || !t)
return 1;

d = libusb_open_device_with_vid_pid(NULL, vid, pid);
if (!d)
return 2;

libusb_detach_kernel_driver(d, ifc);
r = libusb_claim_interface(d, ifc);
if (r)
return 3;

libusb_fill_interrupt_transfer(t, d, ep, bufi, sizeof(bufi), comp, NULL, 0);

for (;;) {
/* GET_STATUS(DEVICE) */
r = libusb_control_transfer(d, 0x80, 0, 0, 0, bufc, sizeof(bufc), 100);
if (r != sizeof(bufc))
return 4;

r = libusb_submit_transfer(t);
if (r)
return 5;
r = libusb_cancel_transfer(t);
if (r)
return 6;
r = libusb_handle_events(NULL);
if (r)
return 7;
}
}

int main (int argc, char **argv) {
int vid, pid, ifc, ep;
int r;

if (argc != 5) {
fprintf(stderr, "USAGE: %s vid pid ifc ep\n", argv[0]);
return 1;
}

vid = strtol(argv[1], NULL, 16);
pid = strtol(argv[2], NULL, 16);
ifc = strtol(argv[3], NULL, 16);
ep = strtol(argv[4], NULL, 16);

r = hammer(vid, pid, ifc, ep);
printf("%d\n", r);
}