summaryrefslogtreecommitdiff
path: root/sanei
diff options
context:
space:
mode:
Diffstat (limited to 'sanei')
-rw-r--r--sanei/sanei_usb.c171
1 files changed, 92 insertions, 79 deletions
diff --git a/sanei/sanei_usb.c b/sanei/sanei_usb.c
index 7401658..f210d4f 100644
--- a/sanei/sanei_usb.c
+++ b/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;
@@ -460,8 +461,6 @@ sanei_libusb_strerror (int errcode)
default:
return "Unknown libusb-1.0 error code";
}
-
- return "Unknown libusb-1.0 error code";
}
#endif /* HAVE_LIBUSB_1_0 */
@@ -635,6 +634,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 +821,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 +845,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 +992,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 +1019,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__,
@@ -1381,30 +1383,32 @@ sanei_usb_open (SANE_String_Const devname, SANE_Int * dn)
"configuration (%d), choosing first config (%d)\n",
dev->descriptor.bNumConfigurations,
dev->config[0].bConfigurationValue);
- }
- result = usb_set_configuration (devices[devcount].libusb_handle,
- dev->config[0].bConfigurationValue);
- if (result < 0)
- {
- SANE_Status status = SANE_STATUS_INVAL;
- DBG (1, "sanei_usb_open: libusb complained: %s\n", usb_strerror ());
- if (errno == EPERM || errno == EACCES)
- {
- DBG (1, "Make sure you run as root or set appropriate "
- "permissions\n");
- status = SANE_STATUS_ACCESS_DENIED;
- }
- else if (errno == EBUSY)
- {
- DBG (3, "Maybe the kernel scanner driver or usblp claims the "
- "interface? Ignoring this error...\n");
- status = SANE_STATUS_GOOD;
- }
- if (status != SANE_STATUS_GOOD)
+ result = usb_set_configuration (devices[devcount].libusb_handle,
+ dev->config[0].bConfigurationValue);
+ if (result < 0)
{
- usb_close (devices[devcount].libusb_handle);
- return status;
+ SANE_Status status = SANE_STATUS_INVAL;
+
+ DBG (1, "sanei_usb_open: libusb complained: %s\n",
+ usb_strerror ());
+ if (errno == EPERM || errno == EACCES)
+ {
+ DBG (1, "Make sure you run as root or set appropriate "
+ "permissions\n");
+ status = SANE_STATUS_ACCESS_DENIED;
+ }
+ else if (errno == EBUSY)
+ {
+ DBG (3, "Maybe the kernel scanner driver or usblp claims the "
+ "interface? Ignoring this error...\n");
+ status = SANE_STATUS_GOOD;
+ }
+ if (status != SANE_STATUS_GOOD)
+ {
+ usb_close (devices[devcount].libusb_handle);
+ return status;
+ }
}
}
@@ -1445,13 +1449,13 @@ sanei_usb_open (SANE_String_Const devname, SANE_Int * dn)
DBG (5, "sanei_usb_open: interface nr: %d\n", i);
DBG (5, "sanei_usb_open: alt_setting nr: %d\n", a);
- /* Start by interfaces found in sanei_usb_init */
- if (c == 0 && i != devices[devcount].interface_nr)
- {
- DBG (5, "sanei_usb_open: interface %d not detected as "
- "a scanner by sanei_usb_init, ignoring.\n", i);
- continue;
- }
+ /* Start by interfaces found in sanei_usb_init */
+ if (c == 0 && i != devices[devcount].interface_nr)
+ {
+ DBG (5, "sanei_usb_open: interface %d not detected as "
+ "a scanner by sanei_usb_init, ignoring.\n", i);
+ continue;
+ }
interface = &dev->config[c].interface[i].altsetting[a];
@@ -1672,37 +1676,40 @@ sanei_usb_open (SANE_String_Const devname, SANE_Int * dn)
"configuration (%d), choosing first config (%d)\n",
desc.bNumConfigurations,
config0->bConfigurationValue);
- }
- result = libusb_set_configuration (devices[devcount].lu_handle,
- config0->bConfigurationValue);
- libusb_free_config_descriptor (config0);
+ result = 0;
+ if (config != config0->bConfigurationValue)
+ result = libusb_set_configuration (devices[devcount].lu_handle,
+ config0->bConfigurationValue);
- if (result < 0)
- {
- SANE_Status status = SANE_STATUS_INVAL;
-
- DBG (1, "sanei_usb_open: libusb complained: %s\n",
- sanei_libusb_strerror (result));
- if (result == LIBUSB_ERROR_ACCESS)
- {
- DBG (1, "Make sure you run as root or set appropriate "
- "permissions\n");
- status = SANE_STATUS_ACCESS_DENIED;
- }
- else if (result == LIBUSB_ERROR_BUSY)
+ if (result < 0)
{
- DBG (3, "Maybe the kernel scanner driver or usblp claims the "
- "interface? Ignoring this error...\n");
- status = SANE_STATUS_GOOD;
- }
+ SANE_Status status = SANE_STATUS_INVAL;
- if (status != SANE_STATUS_GOOD)
- {
- libusb_close (devices[devcount].lu_handle);
- return status;
+ DBG (1, "sanei_usb_open: libusb complained: %s\n",
+ sanei_libusb_strerror (result));
+ if (result == LIBUSB_ERROR_ACCESS)
+ {
+ DBG (1, "Make sure you run as root or set appropriate "
+ "permissions\n");
+ status = SANE_STATUS_ACCESS_DENIED;
+ }
+ else if (result == LIBUSB_ERROR_BUSY)
+ {
+ DBG (3, "Maybe the kernel scanner driver or usblp claims "
+ "the interface? Ignoring this error...\n");
+ status = SANE_STATUS_GOOD;
+ }
+
+ if (status != SANE_STATUS_GOOD)
+ {
+ libusb_close (devices[devcount].lu_handle);
+ libusb_free_config_descriptor (config0);
+ return status;
+ }
}
}
+ libusb_free_config_descriptor (config0);
/* Claim the interface */
result = libusb_claim_interface (devices[devcount].lu_handle,
@@ -2128,22 +2135,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 +2177,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 +2185,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 +2205,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 +3049,8 @@ sanei_usb_set_altinterface (SANE_Int dn, SANE_Int alternate)
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__)