I recently got a hp officejet 4500.  it's a 3-in-1 printer/scanner/fax.
printing works great with the hplip packages.  scanning doesn't work at
all.

I tracked the problem to read() failing in usb_bulk_read() in libusb.
errno was EINTR.  so I made this function just continue when read() got
EINTR.  I could then scan, but not very reliably.

so I went into the kernel, and tracked it to usbdi_util.c:

@ usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_ha

        error = tsleep((caddr_t)xfer, PZERO | PCATCH, lbl, 0);
        splx(s);
        if (error) {
                DPRINTF(("usbd_bulk_transfer: tsleep=%d\n", error));
                usbd_abort_pipe(pipe);
                return (USBD_INTERRUPTED);
        }

on a hunch, I changed 'PZERO | PCATCH' to 'PWAIT'.  then scanning became
100% reliable.  even full-page 1200dpi (~525MB of data) worked
perfectly.

great.  but, what if we need to interrupt the transfer.  we don't want
to hang here.

well, this function takes a timeout.  so, it's possible to make it
return, even if the transfer stalls.  but is this used?  I looked
at the ports that use libusb.  setting 0/infinite timeout for bulk
transfers is extremely rare, only set in code marked experimental
or problematic.  in the kernel, there are however some callers that
use USBD_NO_TIMEOUT.

so, I offer the following.  if there's no timeout, behave like we do
now and catch signals, and if there's a timeout, ignore signals.

I did the same for interrupt transfers because the situation seems
to be the same.

thoughts?

-- 
jake...@sdf.lonestar.org
SDF Public Access UNIX System - http://sdf.lonestar.org

Index: usbdi_util.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdi_util.c,v
retrieving revision 1.25
diff -u -p usbdi_util.c
--- usbdi_util.c        26 Jun 2008 05:42:19 -0000      1.25
+++ usbdi_util.c        8 Dec 2010 04:58:49 -0000
@@ -426,7 +426,7 @@ usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_ha
     u_int16_t flags, u_int32_t timeout, void *buf, u_int32_t *size, char *lbl)
 {
        usbd_status err;
-       int s, error;
+       int s, error, pri;
 
        usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout,
            usbd_bulk_transfer_cb);
@@ -437,7 +437,8 @@ usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_ha
                splx(s);
                return (err);
        }
-       error = tsleep((caddr_t)xfer, PZERO | PCATCH, lbl, 0);
+       pri = timeout == USBD_NO_TIMEOUT ? (PZERO | PCATCH) : PWAIT;
+       error = tsleep((caddr_t)xfer, pri, lbl, 0);
        splx(s);
        if (error) {
                DPRINTF(("usbd_bulk_transfer: tsleep=%d\n", error));
@@ -467,7 +468,7 @@ usbd_intr_transfer(usbd_xfer_handle xfer, usbd_pipe_ha
     u_int16_t flags, u_int32_t timeout, void *buf, u_int32_t *size, char *lbl)
 {
        usbd_status err;
-       int s, error;
+       int s, error, pri;
 
        usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout,
            usbd_intr_transfer_cb);
@@ -478,7 +479,8 @@ usbd_intr_transfer(usbd_xfer_handle xfer, usbd_pipe_ha
                splx(s);
                return (err);
        }
-       error = tsleep(xfer, PZERO | PCATCH, lbl, 0);
+       pri = timeout == USBD_NO_TIMEOUT ? (PZERO | PCATCH) : PWAIT;
+       error = tsleep(xfer, pri, lbl, 0);
        splx(s);
        if (error) {
                DPRINTF(("usbd_intr_transfer: tsleep=%d\n", error));

Reply via email to