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));