apple / cups

Apple CUPS Sources
https://www.cups.org
Apache License 2.0
1.91k stars 464 forks source link

Add back-channel support to libusb-based USB backend #2890

Closed michaelrsweet closed 12 years ago

michaelrsweet commented 16 years ago

Version: 1.5-feature CUPS.org User: mike

Note: This may not end up in CUPS 1.4!

Currently the libusb-based USB backend does not support back-channel data. Unfortunately, the current "stable" libusb release does not support asynchronous I/O, and it is not clear whether multiple threads can be used to issue simultaneous reads and writes, which is what would be required to properly implement back-channel support. The new libusb branch is currently too unstable to use for development but does add support for asynchronous I/O.

A further complication is that many printers do not actually implement back-channel support properly - basically any read returns the 1284 device ID, which has serious performance implications and is why back-channel is disabled for so many vendors in the legacy UNIX character device implementation.

michaelrsweet commented 13 years ago

CUPS.org User: jhathaway

In the current release 1.5, is back-channel data unsupported on linux with libusb, pending this request?

michaelrsweet commented 13 years ago

CUPS.org User: mike

Jesse,

Yes.

michaelrsweet commented 12 years ago

CUPS.org User: till.kamppeter

I have now added backchannel/bi-di functionality to the libusb-based USB CUPS backend for Linux. First I have ported the backend to libusb-1.0.x, to get an upstream-supported version of libusb and a more sophisticated API (http://www.cups.org/str.php?L3477 and patch attached there). Then I have taken this libusb-1.0.x-based backend and merged it with the libpthread-based multi-threading of the Darwin (Mac OS X) version of the backend (backend/usb-darwin.c), resulting in the attached replacement for backend/usb-libusb.c. The file and the patch can be used with both CUPS 1.5.x and 1.6.x, as from 1.5.x to 1.6.x the file backend/usb-libusb.c did not change. To test, simply apply the patch or replace the file and compile normally, taking care to build the libusb-based version of the USB backend.

To test, set up a PostScript printer with the USB backend and the Manufacturer-supplied PPD file. Make sure that the USB backend gets actually used, as automatic printer setup mechanisms will use HPLIP's "hp" backend for HP printers.

Now look for the option settings in a printer setup tool, especially the "Installed options" group. Do not adjust them to the printers actual state, or bring them into a wrong state if they are correct by accident. Close the printer setup tool.

Now run the command

echo -en '#CUPS-COMMAND\nAutoConfigure\n' | lpr -P

and wait for the job to finish (printer stops blinking, queue empty).

Look into the option settings in your printer setup tool again. Now they should be set to the printer's current state.

The command line sends a command file into the print queue. CUPS recognizes the input as a command file and runs the command execution driver for PostScript printers (commandtops) which sends PostScript query commands to the printer. The printer answers them and thanks to the new bi-directional USB backend the answers get back to the driver and the driver tells the CUPS daemon how to set the option.

Before, this worked only either with network-connected printers or with the USB backend when built for the usblp kernel module. Now the usblp kernel module can really get retired.

Note: Command execution on PostScript printers does not work with CUPS 1.5.0 due to a bug. 1.5.1 or newer is required (or a current snapshot of CUPS 1.6.x).

michaelrsweet commented 12 years ago

CUPS.org User: mike

Fixed in Subversion repository.

Changes will also show up in the next 1.5.x release.

michaelrsweet commented 12 years ago

CUPS.org User: till.kamppeter

Mike, can you also change the build system so that the libusb-based "usb" backend will get built by default?

The libusb-based backend has once more functionality, especially bi-di works with all printers, without any manufacturer-wise restrictions, and second, it works also in systems with usblp module present, as it detaches the module from the printer before communicating and reattaches the module after finishing the communication. This means that it always "just works". The usblp-based backend is now only a fallback solution for systems without libusb.

michaelrsweet commented 12 years ago

CUPS.org User: mike

Till, I thought we already preferred libusb over the character device stuff, but I'll double-check and update as needed...

michaelrsweet commented 12 years ago

CUPS.org User: mike

OK, the logic was backwards so I've updated the configure script to use libusb by default unless we are running Mac OS X.

michaelrsweet commented 12 years ago

"usb-backend-backchannel-support-1.5.x.patch":

--- backend/usb-libusb.c.orig 2012-02-05 23:07:15.454577212 +0100 +++ backend/usb-libusb.c 2012-02-08 22:17:59.782785873 +0100 @@ -13,26 +13,53 @@ *

-#include -#include +#include

include <cups/cups-private.h>

+#include +#include <sys/select.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include

+#define PARSE_PS_ERRORS 1 + +/*

+typedef struct globals_s +{

+static void _read_thread(void reference); +static void sidechannel_thread(void reference); static int close_device(usb_printer_t printer); static usb_printer_t find_device(usb_cb_t cb, const void data); static int get_device_id(usb_printer_t printer, char buffer, @@ -69,7 +137,11 @@ 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 ssize_t side_cb(usb_printer_t printer, int print_fd); +static void soft_reset(void); +#ifdef PARSE_PS_ERRORS +static const char next_line (const char buffer); +static void parsepserror (char *sockBuffer, int len); +#endif / PARSE_PS_ERRORS */

/ @@ -98,27 +170,47 @@ int argc, /* I - Number of command-line arguments (6 or 7) _/ char argv[]) /_ I - Command-line arguments */ {

@@ -136,74 +228,609 @@ sigaction(SIGTERM, &action, NULL); }

- */

@@ -214,6 +841,11 @@ static int /* I - 0 on success, -1 on failure _/ close_device(usb_printert *printer) / I - Printer */ {

- usb_release_interface(printer->handle, number);

@@ -249,15 +892,21 @@ find_device(usb_cbt cb, /* I - Callback function / const void data) /_ I - User data for callback / {

@@ -409,10 +1069,12 @@ int length; /* Length of device ID */

@@ -657,7 +1343,7 @@

- */

@@ -747,7 +1468,7 @@ if (verbose) fputs("STATE: -connecting-to-device\n", stderr);

-static ssizet /* O - Number of bytes written / -side_cb(usb_printert *printer, / I - Printer */

- status = CUPS_SC_STATUS_OK;

- break;

michaelrsweet commented 12 years ago

"str2890.patch":

Index: backend/usb-libusb.c

--- backend/usb-libusb.c (revision 10264) +++ backend/usb-libusb.c (working copy) @@ -13,16 +13,18 @@ *

-static libusb_device list; / List of connected USB devices / +#define WAIT_EOF 0 +#define WAIT_EOF_DELAY 7 +#define WAIT_SIDE_DELAY 3 +#define DEFAULT_TIMEOUT 5000L

/ @@ -53,6 +64,7 @@ altset, /* Alternate setting _/ writeendp, / Write endpoint _/ readendp, / Read endpoint /

+typedef struct usb_globals_s +{

@@ -78,7 +124,9 @@ 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 ssize_t side_cb(usb_printer_t printer, int print_fd); +static void read_thread(void reference); +static void sidechannel_thread(void reference); +static void soft_reset(void);

/ @@ -107,28 +155,46 @@ int argc, /* I - Number of command-line arguments (6 or 7) _/ char argv[]) /_ I - Command-line arguments */ {

@@ -236,6 +592,7 @@ struct libusb_config_descriptor confptr; / Pointer to current configuration */

+ if (printer->handle) { / @@ -243,10 +600,12 @@ * to the device... /

@@ -398,10 +761,11 @@

  if (protocol > 0)
  {

-#ifdef APPLE /*

- */

- if (!mfg)

-#else

@@ -740,27 +1094,20 @@

/*

- }

- libusb_get_config_descriptor(printer->device, printer->conf, &confptr);

@@ -790,12 +1137,10 @@ else if (errcode == 1) {

printer->usblp_attached = 1;

 if ((errcode =
 libusb_detach_kernel_driver(printer->handle, printer->iface)) < 0)
 {

@@ -815,42 +1158,44 @@ */

number1 = confptr->interface[printer->iface].

-static ssizet /* O - Number of bytes written / -side_cb(usb_printert *printer, / I - Printer */

- return (-1);

- }