Description: work around USB3/xhci problems in Linux. Backport from upstream. Author: m. allan noah Origin: upstream,http://anonscm.debian.org/cgit/sane/sane-backends.git/commit/?id=014b45d920f1fb630e1a31bb01f1da02ea2a6a87 Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=738592 Forwarded: not-needed Last-Update: 2014-12-26 --- This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ Index: trunk/sanei/sanei_usb.c =================================================================== --- trunk.orig/sanei/sanei_usb.c +++ trunk/sanei/sanei_usb.c @@ -154,6 +154,7 @@ typedef struct SANE_Int control_in_ep; SANE_Int control_out_ep; SANE_Int interface_nr; + SANE_Int alt_setting; SANE_Int missing; #ifdef HAVE_LIBUSB usb_dev_handle *libusb_handle; @@ -635,6 +636,7 @@ static void usbcall_scan_devices(void) device.product = pDevDesc->idProduct; device.method = sanei_usb_method_usbcalls; device.interface_nr = interface; + device.alt_setting = 0; DBG (4, "%s: found usbcalls device (0x%04x/0x%04x) as device number %s\n", __func__, pDevDesc->idVendor, pDevDesc->idProduct,device.devname); store_device(device); @@ -821,7 +823,7 @@ static void libusb_scan_devices(void) "scanner (%d/%d)\n", __func__, dev->descriptor.idVendor, dev->descriptor.idProduct, interface, dev->descriptor.bDeviceClass, - dev->config[0].interface[interface].altsetting != 0 + dev->config[0].interface[interface].num_altsetting != 0 ? dev->config[0].interface[interface].altsetting[0]. bInterfaceClass : -1); } @@ -845,6 +847,7 @@ static void libusb_scan_devices(void) device.product = dev->descriptor.idProduct; device.method = sanei_usb_method_libusb; device.interface_nr = interface; + device.alt_setting = 0; DBG (4, "%s: found libusb device (0x%04x/0x%04x) interface " "%d at %s\n", __func__, @@ -991,7 +994,7 @@ static void libusb_scan_devices(void) "%s: device 0x%04x/0x%04x, interface %d " "doesn't look like a scanner (%d/%d)\n", __func__, vid, pid, interface, desc.bDeviceClass, - (config0->interface[interface].altsetting != 0) + (config0->interface[interface].num_altsetting != 0) ? config0->interface[interface].altsetting[0].bInterfaceClass : -1); } @@ -1018,6 +1021,7 @@ static void libusb_scan_devices(void) device.product = pid; device.method = sanei_usb_method_libusb; device.interface_nr = interface; + device.alt_setting = 0; DBG (4, "%s: found libusb-1.0 device (0x%04x/0x%04x) interface " "%d at %s\n", __func__, @@ -2128,22 +2132,24 @@ sanei_usb_close (SANE_Int dn) else #ifdef HAVE_LIBUSB { -#if 0 - /* Should only be done in case of a stall */ - usb_clear_halt (devices[dn].libusb_handle, devices[dn].bulk_in_ep); - usb_clear_halt (devices[dn].libusb_handle, devices[dn].bulk_out_ep); - usb_clear_halt (devices[dn].libusb_handle, devices[dn].iso_in_ep); - /* be careful, we don't know if we are in DATA0 stage now */ - usb_resetep (devices[dn].libusb_handle, devices[dn].bulk_in_ep); - usb_resetep (devices[dn].libusb_handle, devices[dn].bulk_out_ep); - usb_resetep (devices[dn].libusb_handle, devices[dn].iso_in_ep); -#endif /* 0 */ + /* This call seems to be required by Linux xhci driver + * even though it should be a no-op. Without it, the + * host or driver does not reset it's data toggle bit. + * We intentionally ignore the return val */ + sanei_usb_set_altinterface (dn, devices[dn].alt_setting); + usb_release_interface (devices[dn].libusb_handle, devices[dn].interface_nr); usb_close (devices[dn].libusb_handle); } #elif defined(HAVE_LIBUSB_1_0) { + /* This call seems to be required by Linux xhci driver + * even though it should be a no-op. Without it, the + * host or driver does not reset it's data toggle bit. + * We intentionally ignore the return val */ + sanei_usb_set_altinterface (dn, devices[dn].alt_setting); + libusb_release_interface (devices[dn].lu_handle, devices[dn].interface_nr); libusb_close (devices[dn].lu_handle); @@ -2168,7 +2174,6 @@ sanei_usb_set_timeout (SANE_Int timeout) SANE_Status sanei_usb_clear_halt (SANE_Int dn) { -#ifdef HAVE_LIBUSB int ret; if (dn >= device_number || dn < 0) @@ -2177,6 +2182,14 @@ sanei_usb_clear_halt (SANE_Int dn) return SANE_STATUS_INVAL; } +#ifdef HAVE_LIBUSB + + /* This call seems to be required by Linux xhci driver + * even though it should be a no-op. Without it, the + * host or driver does not send the clear to the device. + * We intentionally ignore the return val */ + sanei_usb_set_altinterface (dn, devices[dn].alt_setting); + ret = usb_clear_halt (devices[dn].libusb_handle, devices[dn].bulk_in_ep); if (ret){ DBG (1, "sanei_usb_clear_halt: BULK_IN ret=%d\n", ret); @@ -2189,18 +2202,13 @@ sanei_usb_clear_halt (SANE_Int dn) return SANE_STATUS_INVAL; } - /* be careful, we don't know if we are in DATA0 stage now - ret = usb_resetep (devices[dn].libusb_handle, devices[dn].bulk_in_ep); - ret = usb_resetep (devices[dn].libusb_handle, devices[dn].bulk_out_ep); - */ #elif defined(HAVE_LIBUSB_1_0) - int ret; - if (dn >= device_number || dn < 0) - { - DBG (1, "sanei_usb_clear_halt: dn >= device number || dn < 0\n"); - return SANE_STATUS_INVAL; - } + /* This call seems to be required by Linux xhci driver + * even though it should be a no-op. Without it, the + * host or driver does not send the clear to the device. + * We intentionally ignore the return val */ + sanei_usb_set_altinterface (dn, devices[dn].alt_setting); ret = libusb_clear_halt (devices[dn].lu_handle, devices[dn].bulk_in_ep); if (ret){ @@ -3038,6 +3046,8 @@ sanei_usb_set_altinterface (SANE_Int dn, DBG (5, "sanei_usb_set_altinterface: alternate = %d\n", alternate); + devices[dn].alt_setting = alternate; + if (devices[dn].method == sanei_usb_method_scanner_driver) { #if defined(__linux__) Index: trunk/ChangeLog =================================================================== --- trunk.orig/ChangeLog +++ trunk/ChangeLog @@ -1,3 +1,9 @@ +2014-12-16 m. allan noah + * sanei/sanei_usb.c: add calls to sanei_usb_set_altinterface in + sanei_usb_close and sanei_usb_clear_halt- hopefully work around + USB3/xhci problems in Linux. + + ****** Release of sane-backends 1.0.24. End of code freeze ****** 2013-09-30 m. allan noah