Re: [MOD] STR #4128: libusb-based USB backend: Further fixes
Till Kamppeter <[email protected]>
| Newsgroups | gmane.comp.printing.cups.bugs |
|---|---|
| Message-ID | <[email protected]> |
DO NOT REPLY TO THIS MESSAGE. INSTEAD, POST ANY RESPONSES TO THE LINK BELOW. [STR New] Attached file "usb-libusb-c-update-1-5-x.patch"... Link: http://www.cups.org/str.php?L4128 Version: 1.6-current _______________________________________________ cups-bugs mailing list [email protected] http://lists.easysw.com/mailman/listinfo/cups-bugs
usb-libusb-c-update-1-5-x.patch
(text/plain, 13 KB)
--- backend/usb-libusb.c 2012-06-22 11:53:36.103353715 +0200
+++ backend/usb-libusb.c 2012-06-22 11:52:50.723163432 +0200
@@ -22,6 +22,8 @@
* make_device_uri() - Create a device URI for a USB printer.
* open_device() - Open a connection to the USB printer.
* print_cb() - Find a USB printer for printing.
+ * printer_class_soft_reset()' - Do the soft reset request specific to
+ * printers
* read_thread() - Thread to read the backchannel data on.
* sidechannel_thread() - Handle side-channel requests.
* soft_reset() - Send a soft reset to the device.
@@ -60,12 +62,13 @@
{
struct libusb_device *device; /* Device info */
int conf, /* Configuration */
+ origconf, /* Original configuration */
iface, /* Interface */
altset, /* Alternate setting */
write_endp, /* Write endpoint */
- read_endp, /* Read endpoint */
+ read_endp, /* Read endpoint */
protocol, /* Protocol: 1 = Uni-di, 2 = Bi-di. */
- usblp_attached; /* Is the "usblp" kernel module
+ usblp_attached; /* Is the "usblp" kernel module
attached? */
struct libusb_device_handle *handle; /* Open handle to device */
} usb_printer_t;
@@ -124,6 +127,7 @@
static int open_device(usb_printer_t *printer, int verbose);
static int print_cb(usb_printer_t *printer, const char *device_uri,
const char *device_id, const void *data);
+static int printer_class_soft_reset(usb_printer_t *printer);
static void *read_thread(void *reference);
static void *sidechannel_thread(void *reference);
static void soft_reset(void);
@@ -163,7 +167,8 @@
iostatus; /* Current IO status */
pthread_t read_thread_id, /* Read thread */
sidechannel_thread_id; /* Side-channel thread */
- int have_sidechannel = 0; /* Was the side-channel thread started? */
+ int have_sidechannel = 0, /* Was the side-channel thread started? */
+ have_backchannel = 0; /* Do we have a back channel? */
struct stat sidechannel_info; /* Side-channel file descriptor info */
unsigned char print_buffer[8192], /* Print data buffer */
*print_ptr; /* Pointer into print data buffer */
@@ -172,6 +177,9 @@
struct timeval *timeout, /* Timeout pointer */
tv; /* Time value */
struct timespec cond_timeout; /* pthread condition timeout */
+ int num_opts; /* Number of options */
+ cups_option_t *opts; /* Options */
+ const char *val; /* Option value */
/*
@@ -187,6 +195,7 @@
* Connect to the printer...
*/
+ fprintf(stderr, "DEBUG: Printing on printer with URI: %s\n", uri);
while ((g.printer = find_device(print_cb, uri)) == NULL)
{
_cupsLangPrintFilter(stderr, "INFO",
@@ -240,24 +249,47 @@
}
/*
- * Get the read thread going...
+ * Debug mode: If option "usb-unidir" is given, always deactivate
+ * backchannel
*/
- g.read_thread_stop = 0;
- g.read_thread_done = 0;
+ num_opts = cupsParseOptions(argv[5], 0, &opts);
+ val = cupsGetOption("usb-unidir", num_opts, opts);
+ if (val && strcasecmp(val, "no") && strcasecmp(val, "off") &&
+ strcasecmp(val, "false"))
+ {
+ g.printer->read_endp = -1;
+ fprintf(stderr, "DEBUG: Forced uni-directional communication "
+ "via \"usb-unidir\" option.\n");
+ }
- pthread_cond_init(&g.read_thread_cond, NULL);
- pthread_mutex_init(&g.read_thread_mutex, NULL);
+ /*
+ * Get the read thread going...
+ */
- if (pthread_create(&read_thread_id, NULL, read_thread, NULL))
+ if (g.printer->read_endp != -1)
{
- fprintf(stderr, "DEBUG: Fatal USB error.\n");
- _cupsLangPrintFilter(stderr, "ERROR",
- _("There was an unrecoverable USB error."));
- fputs("DEBUG: Couldn't create read thread.\n", stderr);
- close_device(g.printer);
- return (CUPS_BACKEND_STOP);
+ have_backchannel = 1;
+
+ g.read_thread_stop = 0;
+ g.read_thread_done = 0;
+
+ pthread_cond_init(&g.read_thread_cond, NULL);
+ pthread_mutex_init(&g.read_thread_mutex, NULL);
+
+ if (pthread_create(&read_thread_id, NULL, read_thread, NULL))
+ {
+ fprintf(stderr, "DEBUG: Fatal USB error.\n");
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("There was an unrecoverable USB error."));
+ fputs("DEBUG: Couldn't create read thread.\n", stderr);
+ close_device(g.printer);
+ return (CUPS_BACKEND_STOP);
+ }
}
+ else
+ fprintf(stderr, "DEBUG: Uni-directional device/mode, back channel "
+ "deactivated.\n");
/*
* The main thread sends the print file...
@@ -515,50 +547,54 @@
* Signal the read thread to exit then wait 7 seconds for it to complete...
*/
- g.read_thread_stop = 1;
-
- pthread_mutex_lock(&g.read_thread_mutex);
-
- if (!g.read_thread_done)
+ if (have_backchannel)
{
- fputs("DEBUG: Waiting for read thread to exit...\n", stderr);
-
- gettimeofday(&tv, NULL);
- cond_timeout.tv_sec = tv.tv_sec + WAIT_EOF_DELAY;
- cond_timeout.tv_nsec = tv.tv_usec * 1000;
+ g.read_thread_stop = 1;
- while (!g.read_thread_done)
- {
- if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex,
- &cond_timeout) != 0)
- break;
- }
+ pthread_mutex_lock(&g.read_thread_mutex);
- /*
- * If it didn't exit abort the pending read and wait an additional second...
- */
-
if (!g.read_thread_done)
{
- fputs("DEBUG: Read thread still active, aborting the pending read...\n",
- stderr);
-
- g.wait_eof = 0;
+ fputs("DEBUG: Waiting for read thread to exit...\n", stderr);
gettimeofday(&tv, NULL);
- cond_timeout.tv_sec = tv.tv_sec + 1;
+ cond_timeout.tv_sec = tv.tv_sec + WAIT_EOF_DELAY;
cond_timeout.tv_nsec = tv.tv_usec * 1000;
-
+
while (!g.read_thread_done)
{
if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex,
&cond_timeout) != 0)
break;
}
+
+ /*
+ * If it didn't exit abort the pending read and wait an additional
+ * second...
+ */
+
+ if (!g.read_thread_done)
+ {
+ fputs("DEBUG: Read thread still active, aborting the pending read...\n",
+ stderr);
+
+ g.wait_eof = 0;
+
+ gettimeofday(&tv, NULL);
+ cond_timeout.tv_sec = tv.tv_sec + 1;
+ cond_timeout.tv_nsec = tv.tv_usec * 1000;
+
+ while (!g.read_thread_done)
+ {
+ if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex,
+ &cond_timeout) != 0)
+ break;
+ }
+ }
}
- }
- pthread_mutex_unlock(&g.read_thread_mutex);
+ pthread_mutex_unlock(&g.read_thread_mutex);
+ }
if (print_fd)
close(print_fd);
@@ -601,24 +637,51 @@
*/
int errcode; /* Return value of libusb function */
- int number; /* Interface number */
+ int number1, /* Interface number */
+ number2; /* Configuration number */
errcode =
libusb_get_config_descriptor (printer->device, printer->conf, &confptr);
if (errcode >= 0)
{
- number = confptr->interface[printer->iface].
+ number1 = confptr->interface[printer->iface].
altsetting[printer->altset].bInterfaceNumber;
- libusb_release_interface(printer->handle, number);
- if (number != 0)
- libusb_release_interface(printer->handle, 0);
+ libusb_release_interface(printer->handle, number1);
+
+ number2 = confptr->bConfigurationValue;
+
+ libusb_free_config_descriptor(confptr);
+
+ /*
+ * If we have changed the configuration, restore the old one
+ */
+ if (printer->origconf != number2)
+ fprintf(stderr, "DEBUG: Restoring USB device configuration: %d -> %d\n",
+ number2, printer->origconf);
+ if ((errcode = libusb_set_configuration(printer->handle,
+ printer->origconf)) < 0)
+ {
+ if (errcode != LIBUSB_ERROR_BUSY)
+ {
+ errcode =
+ libusb_get_device_descriptor (printer->device, &devdesc);
+ if (errcode < 0)
+ fprintf(stderr,
+ "DEBUG: Failed to set configuration %d\n",
+ printer->origconf);
+ else
+ fprintf(stderr,
+ "DEBUG: Failed to set configuration %d for %04x:%04x\n",
+ printer->origconf, devdesc.idVendor, devdesc.idProduct);
+ }
+ }
/*
* Re-attach "usblp" kernel module if it was attached before using this
* device
*/
if (printer->usblp_attached == 1)
- if (libusb_attach_kernel_driver(printer->handle, printer->iface) < 0)
+ if (libusb_attach_kernel_driver(printer->handle, number1) < 0)
{
errcode = libusb_get_device_descriptor (printer->device, &devdesc);
if (errcode < 0)
@@ -629,9 +692,11 @@
"DEBUG: Failed to re-attach \"usblp\" kernel module to "
"%04x:%04x\n", devdesc.idVendor, devdesc.idProduct);
}
-
- libusb_free_config_descriptor(confptr);
}
+ else
+ fprintf(stderr,
+ "DEBUG: Failed to get configuration descriptor %d\n",
+ printer->conf);
/*
* Close the interface and return...
@@ -764,7 +829,10 @@
protocol = altptr->bInterfaceProtocol;
printer.altset = altset;
printer.write_endp = write_endp;
- printer.read_endp = read_endp;
+ if (protocol > 1)
+ printer.read_endp = read_endp;
+ else
+ printer.read_endp = -1;
}
}
@@ -782,16 +850,29 @@
make_device_uri(&printer, device_id, device_uri,
sizeof(device_uri));
+ fprintf(stderr, "DEBUG: Printer found with device ID: %s "
+ "Device URI: %s\n",
+ device_id, device_uri);
+
if ((*cb)(&printer, device_uri, device_id, data))
{
- printer.read_endp = confptr->interface[printer.iface].
- altsetting[printer.altset].
- endpoint[printer.read_endp].
- bEndpointAddress;
+ fprintf(stderr, "DEBUG: Device protocol: %d\n",
+ printer.protocol);
+ if (printer.read_endp != -1)
+ {
+ printer.read_endp = confptr->interface[printer.iface].
+ altsetting[printer.altset].
+ endpoint[printer.read_endp].
+ bEndpointAddress;
+ }
+ else
+ fprintf(stderr, "DEBUG: Uni-directional USB communication "
+ "only!\n");
printer.write_endp = confptr->interface[printer.iface].
altsetting[printer.altset].
endpoint[printer.write_endp].
bEndpointAddress;
+ libusb_free_config_descriptor(confptr);
return (&printer);
}
@@ -1095,8 +1176,12 @@
* Try opening the printer...
*/
- if (libusb_open(printer->device, &printer->handle) < 0)
+ if ((errcode = libusb_open(printer->device, &printer->handle)) < 0)
+ {
+ fprintf(stderr, "DEBUG: Failed to open device, code: %d\n",
+ errcode);
return (-1);
+ }
printer->usblp_attached = 0;
@@ -1132,14 +1217,9 @@
else
{
printer->usblp_attached = 0;
-
- if (errcode != LIBUSB_ERROR_NOT_SUPPORTED)
- {
- fprintf(stderr,
- "DEBUG: Failed to check whether %04x:%04x has the \"usblp\" "
- "kernel module attached\n", devdesc.idVendor, devdesc.idProduct);
- goto error;
- }
+ fprintf(stderr, "DEBUG: Failed to check whether %04x:%04x has the \"usblp\" kernel module attached\n",
+ devdesc.idVendor, devdesc.idProduct);
+ goto error;
}
/*
@@ -1156,6 +1236,8 @@
0, 0, (unsigned char *)¤t, 1, 5000) < 0)
current = 0; /* Assume not configured */
+ printer->origconf = current;
+
if ((errcode =
libusb_get_config_descriptor (printer->device, printer->conf, &confptr))
< 0)
@@ -1168,6 +1250,8 @@
if (number1 != current)
{
+ fprintf(stderr, "DEBUG: Switching USB device configuration: %d -> %d\n",
+ current, number1);
if ((errcode = libusb_set_configuration(printer->handle, number1)) < 0)
{
/*
@@ -1347,6 +1431,39 @@
/*
+ * 'printer_class_soft_reset()' - Do the soft reset request specific to printers
+ *
+ * This soft reset is specific to the printer device class and is much less
+ * invasive than the general USB reset libusb_reset_device(). Especially it
+ * does never happen that the USB addressing and configuration changes. What
+ * is actually done is that all buffers get flushed and the bulk IN and OUT
+ * pipes get reset to their default states. This clears all stall conditions.
+ * See http://cholla.mmto.org/computers/linux/usb/usbprint11.pdf
+ */
+
+static int /* O - 0 on success, < 0 on error */
+printer_class_soft_reset(usb_printer_t *printer) /* I - Printer */
+{
+ struct libusb_config_descriptor *confptr = NULL;
+ /* Pointer to current configuration */
+ int interface;
+
+ if (libusb_get_config_descriptor (printer->device, printer->conf, &confptr)
+ < 0)
+ interface = printer->iface;
+ else
+ interface = confptr->interface[printer->iface].
+ altsetting[printer->altset].bInterfaceNumber;
+ libusb_free_config_descriptor(confptr);
+ return libusb_control_transfer(printer->handle,
+ LIBUSB_REQUEST_TYPE_CLASS |
+ LIBUSB_ENDPOINT_OUT |
+ LIBUSB_RECIPIENT_INTERFACE,
+ 2, 0, interface, NULL, 0, 5000);
+}
+
+
+/*
* 'read_thread()' - Thread to read the backchannel data on.
*/
@@ -1620,7 +1737,7 @@
* Send the reset...
*/
- libusb_reset_device (g.printer->handle);
+ printer_class_soft_reset (g.printer);
/*
* Release the I/O lock...