On Thu, 21 Jan 2021 15:51:58 +0000
Mikolaj Kucharski <[email protected]> wrote:

> I've also tested scanning on:
> 
> # scanimage -L
> device `xerox_mfp:libusb:000:002' is a Samsung M2070 Series
> multi-function peripheral
> 
> with kernel diff:
> 
>       https://marc.info/?l=openbsd-bugs&m=160991986510827&w=2
> 
> and it works. Is there anything else I can help with to get your diff
> commited to CVS?

Cool, thanks for testing!

We are currently trying to understand whether this data toggle fix for
ugen(4) can also be applied to uhidev(4), since we have the same
problem there.  For uhidev(4) we see it working for some devices, and
for some not.  So I hope we can sort this out soon, and then commit the
whole diff.  I attach the latest diff here again for reference about
what I'm talking (has already been sent out to tech@).


Index: dev/usb/ugen.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ugen.c,v
retrieving revision 1.109
diff -u -p -u -p -r1.109 ugen.c
--- dev/usb/ugen.c      25 Dec 2020 12:59:52 -0000      1.109
+++ dev/usb/ugen.c      13 Jan 2021 21:38:30 -0000
@@ -46,9 +46,12 @@
 #include <sys/vnode.h>
 #include <sys/poll.h>
 
+#include <machine/bus.h>
+
 #include <dev/usb/usb.h>
 #include <dev/usb/usbdi.h>
 #include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbdivar.h>
 
 #ifdef UGEN_DEBUG
 #define DPRINTF(x)     do { if (ugendebug) printf x; } while (0)
@@ -114,6 +117,7 @@ int ugen_do_close(struct ugen_softc *, i
 int ugen_set_config(struct ugen_softc *sc, int configno);
 int ugen_set_interface(struct ugen_softc *, int, int);
 int ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx);
+void ugen_clear_iface_eps(struct ugen_softc *, struct usbd_interface *);
 
 #define UGENUNIT(n) ((minor(n) >> 4) & 0xf)
 #define UGENENDPOINT(n) (minor(n) & 0xf)
@@ -302,6 +306,8 @@ ugenopen(dev_t dev, int flag, int mode, 
                DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n",
                             sc, endpt, dir, sce));
                edesc = sce->edesc;
+               /* Clear device endpoint toggle. */
+               ugen_clear_iface_eps(sc, sce->iface);
                switch (UE_GET_XFERTYPE(edesc->bmAttributes)) {
                case UE_INTERRUPT:
                        if (dir == OUT) {
@@ -329,6 +335,8 @@ ugenopen(dev_t dev, int flag, int mode, 
                                clfree(&sce->q);
                                return (EIO);
                        }
+                       /* Clear HC endpoint toggle. */
+                       usbd_clear_endpoint_toggle(sce->pipeh);
                        DPRINTFN(5, ("ugenopen: interrupt open done\n"));
                        break;
                case UE_BULK:
@@ -336,6 +344,8 @@ ugenopen(dev_t dev, int flag, int mode, 
                                  edesc->bEndpointAddress, 0, &sce->pipeh);
                        if (err)
                                return (EIO);
+                       /* Clear HC endpoint toggle. */
+                       usbd_clear_endpoint_toggle(sce->pipeh);
                        break;
                case UE_ISOCHRONOUS:
                        if (dir == OUT)
@@ -1417,4 +1427,42 @@ ugenkqfilter(dev_t dev, struct knote *kn
        splx(s);
 
        return (0);
+}
+
+void
+ugen_clear_iface_eps(struct ugen_softc *sc, struct usbd_interface *iface)
+{
+       usb_interface_descriptor_t *id;
+       usb_endpoint_descriptor_t *ed;
+       uint8_t xfertype;
+       int i;
+
+       /* Only clear interface endpoints when none are in use. */
+       for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
+               if (i == USB_CONTROL_ENDPOINT)
+                       continue;
+               if (sc->sc_is_open[i] != 0)
+                       return;
+       }
+       DPRINTFN(1,("%s: clear interface eps\n", __func__));
+
+       id = usbd_get_interface_descriptor(iface);
+       if (id == NULL)
+               goto bad;
+
+       for (i = 0; i < id->bNumEndpoints; i++) {
+               ed = usbd_interface2endpoint_descriptor(iface, i);
+               if (ed == NULL)
+                       goto bad;
+
+               xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
+               if (xfertype == UE_BULK || xfertype == UE_INTERRUPT) {
+                       if (usbd_clear_endpoint_feature(sc->sc_udev,
+                           ed->bEndpointAddress, UF_ENDPOINT_HALT))
+                               goto bad;
+               }
+       }
+       return;
+bad:
+       printf("%s: clear endpoints failed!\n", __func__);
 }
Index: dev/usb/uhidev.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uhidev.c,v
retrieving revision 1.83
diff -u -p -u -p -r1.83 uhidev.c
--- dev/usb/uhidev.c    31 Aug 2020 12:26:49 -0000      1.83
+++ dev/usb/uhidev.c    13 Jan 2021 21:38:31 -0000
@@ -98,6 +98,7 @@ int uhidev_activate(struct device *, int
 
 void uhidev_get_report_async_cb(struct usbd_xfer *, void *, usbd_status);
 void uhidev_set_report_async_cb(struct usbd_xfer *, void *, usbd_status);
+void uhidev_clear_iface_eps(struct uhidev_softc *, struct usbd_interface *);
 
 struct cfdriver uhidev_cd = {
        NULL, "uhidev", DV_DULL
@@ -508,6 +509,9 @@ uhidev_open(struct uhidev *scd)
        DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize,
            sc->sc_iep_addr));
 
+       /* Clear device endpoint toggle. */
+       uhidev_clear_iface_eps(sc, sc->sc_iface);
+
        err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_iep_addr,
                  USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_ibuf,
                  sc->sc_isize, uhidev_intr, USBD_DEFAULT_INTERVAL);
@@ -517,6 +521,8 @@ uhidev_open(struct uhidev *scd)
                error = EIO;
                goto out1;
        }
+       /* Clear HC endpoint toggle. */
+       usbd_clear_endpoint_toggle(sc->sc_ipipe);
 
        DPRINTF(("uhidev_open: sc->sc_ipipe=%p\n", sc->sc_ipipe));
 
@@ -542,6 +548,8 @@ uhidev_open(struct uhidev *scd)
                        error = EIO;
                        goto out2;
                }
+               /* Clear HC endpoint toggle. */
+               usbd_clear_endpoint_toggle(sc->sc_opipe);
 
                DPRINTF(("uhidev_open: sc->sc_opipe=%p\n", sc->sc_opipe));
 
@@ -949,4 +957,38 @@ uhidev_ioctl(struct uhidev *sc, u_long c
                return -1;
        }
        return 0;
+}
+
+void
+uhidev_clear_iface_eps(struct uhidev_softc *sc, struct usbd_interface *iface)
+{
+       usb_interface_descriptor_t *id;
+       usb_endpoint_descriptor_t *ed;
+       uint8_t xfertype;
+       int i;
+
+       /* Only clear interface endpoints when none are in use. */
+       if (sc->sc_ipipe || sc->sc_opipe)
+               return;
+       DPRINTFN(1,("%s: clear interface eps\n", __func__));
+
+       id = usbd_get_interface_descriptor(iface);
+       if (id == NULL)
+               goto bad;
+
+       for (i = 0; i < id->bNumEndpoints; i++) {
+               ed = usbd_interface2endpoint_descriptor(iface, i);
+               if (ed == NULL)
+                       goto bad;
+
+               xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
+               if (xfertype == UE_BULK || xfertype == UE_INTERRUPT) {
+                       if (usbd_clear_endpoint_feature(sc->sc_udev,
+                           ed->bEndpointAddress, UF_ENDPOINT_HALT))
+                               goto bad;
+               }
+       }
+       return;
+bad:
+       printf("%s: clear endpoints failed!\n", __func__);
 }
Index: dev/usb/usbdi_util.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdi_util.c,v
retrieving revision 1.44
diff -u -p -u -p -r1.44 usbdi_util.c
--- dev/usb/usbdi_util.c        6 Oct 2019 17:11:51 -0000       1.44
+++ dev/usb/usbdi_util.c        13 Jan 2021 21:38:31 -0000
@@ -192,6 +192,19 @@ usbd_clear_port_feature(struct usbd_devi
 }
 
 usbd_status
+usbd_clear_endpoint_feature(struct usbd_device *dev, int epaddr, int sel)
+{
+       usb_device_request_t req;
+
+       req.bmRequestType = UT_WRITE_ENDPOINT;
+       req.bRequest = UR_CLEAR_FEATURE;
+       USETW(req.wValue, sel);
+       USETW(req.wIndex, epaddr);
+       USETW(req.wLength, 0);
+       return (usbd_do_request(dev, &req, 0));
+}
+
+usbd_status
 usbd_set_port_feature(struct usbd_device *dev, int port, int sel)
 {
        usb_device_request_t req;
Index: dev/usb/usbdi_util.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdi_util.h,v
retrieving revision 1.29
diff -u -p -u -p -r1.29 usbdi_util.h
--- dev/usb/usbdi_util.h        8 Dec 2014 22:00:11 -0000       1.29
+++ dev/usb/usbdi_util.h        13 Jan 2021 21:38:31 -0000
@@ -41,6 +41,7 @@ usbd_status   usbd_set_hub_feature(struct 
 usbd_status    usbd_clear_hub_feature(struct usbd_device *, int);
 usbd_status    usbd_set_port_feature(struct usbd_device *dev, int, int);
 usbd_status    usbd_clear_port_feature(struct usbd_device *, int, int);
+usbd_status    usbd_clear_endpoint_feature(struct usbd_device *, int, int);
 usbd_status    usbd_get_device_status(struct usbd_device *, usb_status_t *);
 usbd_status    usbd_get_hub_status(struct usbd_device *, usb_hub_status_t *);
 usbd_status    usbd_get_hub_descriptor(struct usbd_device *,

Reply via email to