blob: b6e6715deb74b48dbc944f3302bf69c729aeec1f [file] [log] [blame]
# Changes the usb library to hold all of the ippusb interfaces of the
# printer during the lifetime of the program. Originally at the time of
# communication with the printer a thread would claim an interface and
# release it once it was completed. Unfortunately some printers would
# misbehave if one interface was closed while another interface was in
# the process of transferring data.
#
# Once this patch has been reviewed and finalized it will also be sent
# upstream.
From 65ddaf116b03cff15086afc5225fc494dd146169 Mon Sep 17 00:00:00 2001
From: DavieV <davidvalleau@gmail.com>
Date: Mon, 12 Mar 2018 11:34:18 -0700
Subject: [PATCH 2/2] Changing usb code to hold all ippusb interfaces
Some printers behave unexpectedly when an interface is released while
another interface is still in the process of transferring data. So
instead of claiming and releasing interfaces on each connection, simply
hold all of the interfaces while the program is running.
---
src/usb.c | 106 +++++++++++++++++++++++++++++-------------------------
1 file changed, 57 insertions(+), 49 deletions(-)
diff --git a/src/usb.c b/src/usb.c
index b472a29..050343b 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -168,6 +168,46 @@ int get_device_id(struct libusb_device_handle *handle,
return (0);
}
+static void try_detach_kernel_driver(struct usb_sock_t *usb,
+ struct usb_interface *uf) {
+ /* Make kernel release interface */
+ if (libusb_kernel_driver_active(usb->printer, uf->libusb_interface_index) ==
+ 1) {
+ /* Only linux supports this
+ other platforms will fail
+ thus we ignore the error code
+ it either works or it does not */
+ libusb_detach_kernel_driver(usb->printer, uf->libusb_interface_index);
+ }
+}
+
+static int try_claim_usb_interface(struct usb_sock_t *usb,
+ struct usb_interface *uf) {
+ /* Claim the whole interface */
+ int status = 0;
+ do {
+ /* Spinlock-like
+ Libusb does not offer a blocking call
+ so we're left with a spinlock */
+ status = libusb_claim_interface(usb->printer, uf->libusb_interface_index);
+ if (status)
+ NOTE("Failed to claim interface %d, retrying",
+ uf->libusb_interface_index);
+ switch (status) {
+ case LIBUSB_ERROR_NOT_FOUND:
+ ERR("USB Interface did not exist");
+ return -1;
+ case LIBUSB_ERROR_NO_DEVICE:
+ ERR("Printer was removed");
+ return -1;
+ default:
+ break;
+ }
+ } while (status != 0 && !g_options.terminate);
+
+ return 0;
+}
+
struct usb_sock_t *usb_open()
{
int status_lock;
@@ -372,6 +412,23 @@ struct usb_sock_t *usb_open()
goto error;
}
+ /* Try to make the kernel release the usb interface */
+ try_detach_kernel_driver(usb, uf);
+
+ /* Try to claim the usb interface */
+ if (try_claim_usb_interface(usb, uf)) {
+ ERR("Failed to claim usb interface #%d", uf->interface_number);
+ goto error;
+ }
+
+ /* Select the IPP-USB alt setting of the interface */
+ if (libusb_set_interface_alt_setting(
+ usb->printer, uf->libusb_interface_index, uf->interface_alt)) {
+ ERR("Failed to set alt setting for interface #%d",
+ uf->interface_number);
+ goto error;
+ }
+
break;
}
}
@@ -647,45 +704,6 @@ struct usb_conn_t *usb_conn_acquire(struct usb_sock_t *usb)
goto acquire_error;
}
- /* Make kernel release interface */
- if (libusb_kernel_driver_active(usb->printer,
- uf->libusb_interface_index) == 1) {
- /* Only linux supports this
- other platforms will fail
- thus we ignore the error code
- it either works or it does not */
- libusb_detach_kernel_driver(usb->printer,
- uf->libusb_interface_index);
- }
-
- /* Claim the whole interface */
- int status = 0;
- do {
- /* Spinlock-like
- Libusb does not offer a blocking call
- so we're left with a spinlock */
- status = libusb_claim_interface(usb->printer, uf->libusb_interface_index);
- if (status) NOTE("Failed to claim interface %d, retrying", conn->interface_index);
- switch (status) {
- case LIBUSB_ERROR_NOT_FOUND:
- ERR("USB Interface did not exist");
- goto acquire_error;
- case LIBUSB_ERROR_NO_DEVICE:
- ERR("Printer was removed");
- goto acquire_error;
- default:
- break;
- }
- } while (status != 0 && !g_options.terminate);
-
- if (g_options.terminate)
- goto acquire_error;
-
- /* Select the IPP-USB alt setting of the interface */
- libusb_set_interface_alt_setting(usb->printer,
- uf->libusb_interface_index,
- uf->interface_alt);
-
/* Take successfully acquired interface from the pool */
usb->num_taken++;
usb->num_avail--;
@@ -705,16 +723,6 @@ void usb_conn_release(struct usb_conn_t *conn)
struct usb_sock_t *usb = conn->parent;
sem_wait(&usb->pool_manage_lock);
{
- int status = 0;
- do {
- /* Spinlock-like
- libusb does not offer a blocking call
- so we're left with a spinlock */
- status = libusb_release_interface(usb->printer,
- conn->interface->libusb_interface_index);
- if (status) NOTE("Failed to release interface %d, retrying", conn->interface_index);
- } while (status != 0 && !g_options.terminate);
-
/* Return usb interface to pool */
usb->num_taken--;
usb->num_avail++;
--
2.16.2.804.g6dcf76e118-goog