Hi,

on my Lenovo X395 the uvideo(4) follows the current UVC 1.5 spec.  The
message length was increased with each specification, so now the buffer
for probe messages is up to 48 bytes.  On that particular device the
camera sends a USB stall if we only supply the 26 bytes from the
original UVC 1.0 spec.  By increasing the length depending on the UVC
version, and the other diff I sent, my webcam works fine.

Patrick

diff --git a/sys/dev/usb/uvideo.c b/sys/dev/usb/uvideo.c
index 1a9dfc733fa..3cb93158955 100644
--- a/sys/dev/usb/uvideo.c
+++ b/sys/dev/usb/uvideo.c
@@ -67,6 +67,7 @@ struct uvideo_softc {
        struct device                           *sc_videodev;
 
        int                                      sc_enabled;
+       int                                      sc_max_ctrl_size;
        int                                      sc_max_fbuf_size;
        int                                      sc_negotiated_flag;
        int                                      sc_frame_rate;
@@ -725,6 +726,12 @@ uvideo_vc_parse_desc_header(struct uvideo_softc *sc,
        
        sc->sc_desc_vc_header.fix = d;
        sc->sc_desc_vc_header.baInterfaceNr = (uByte *)(d + 1);
+       if (UGETW(d->bcdUVC) < 0x0110)
+               sc->sc_max_ctrl_size = 26;
+       else if (UGETW(d->bcdUVC) < 0x0150)
+               sc->sc_max_ctrl_size = 34;
+       else
+               sc->sc_max_ctrl_size = 48;
 
        return (USBD_NORMAL_COMPLETION);
 }
@@ -1438,7 +1445,7 @@ uvideo_vs_negotiation(struct uvideo_softc *sc, int commit)
        struct usb_video_header_desc *hd;
        struct usb_video_frame_desc *frame;
        uint8_t *p, *cur;
-       uint8_t probe_data[34];
+       uint8_t probe_data[48];
        uint32_t frame_ival, nivals, min, max, step, diff;
        usbd_status error;
        int i, ival_bytes, changed = 0;
@@ -1622,7 +1629,7 @@ uvideo_vs_set_probe(struct uvideo_softc *sc, uint8_t 
*probe_data)
        tmp = tmp << 8;
        USETW(req.wValue, tmp);
        USETW(req.wIndex, sc->sc_vs_cur->iface);
-       USETW(req.wLength, 26);
+       USETW(req.wLength, sc->sc_max_ctrl_size);
 
        pc = (struct usb_video_probe_commit *)probe_data;
 
@@ -1667,7 +1674,7 @@ uvideo_vs_get_probe(struct uvideo_softc *sc, uint8_t 
*probe_data,
        tmp = tmp << 8;
        USETW(req.wValue, tmp);
        USETW(req.wIndex, sc->sc_vs_cur->iface);
-       USETW(req.wLength, 26);
+       USETW(req.wLength, sc->sc_max_ctrl_size);
 
        pc = (struct usb_video_probe_commit *)probe_data;
 
@@ -1710,7 +1717,7 @@ uvideo_vs_set_commit(struct uvideo_softc *sc, uint8_t 
*probe_data)
        tmp = tmp << 8;
        USETW(req.wValue, tmp);
        USETW(req.wIndex, sc->sc_vs_cur->iface);
-       USETW(req.wLength, 26);
+       USETW(req.wLength, sc->sc_max_ctrl_size);
 
        error = usbd_do_request(sc->sc_udev, &req, probe_data);
        if (error) {

Reply via email to