summaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorDidier Raboud <odyx@debian.org>2012-10-25 21:06:09 +0200
committerDidier Raboud <odyx@debian.org>2012-10-25 21:06:09 +0200
commita75966e33dbc3e3e096338fd332f515cb313b58a (patch)
tree55daa4cc36ac303f40a1b7491f21143bc849d386 /backend
parentb1469ea9a3a5b5b652dcd733f7d419dd1fdfe844 (diff)
downloadcups-a75966e33dbc3e3e096338fd332f515cb313b58a.tar.gz
Imported Upstream version 1.5.4upstream/1.5.4
Diffstat (limited to 'backend')
-rw-r--r--backend/ipp.c40
-rw-r--r--backend/usb-libusb.c488
2 files changed, 410 insertions, 118 deletions
diff --git a/backend/ipp.c b/backend/ipp.c
index e27f38ee..91524a82 100644
--- a/backend/ipp.c
+++ b/backend/ipp.c
@@ -1,5 +1,5 @@
/*
- * "$Id: ipp.c 10452 2012-05-04 23:00:01Z mike $"
+ * "$Id: ipp.c 10509 2012-05-23 22:47:10Z mike $"
*
* IPP backend for CUPS.
*
@@ -62,7 +62,8 @@ typedef struct _cups_monitor_s /**** Monitoring data ****/
*resource; /* Resource path */
int port, /* Port number */
version, /* IPP version */
- job_id; /* Job ID for submitted job */
+ job_id, /* Job ID for submitted job */
+ get_job_attrs; /* Support Get-Job-Attributes? */
const char *job_name; /* Job name for submitted job */
http_encryption_t encryption; /* Use encryption? */
ipp_jstate_t job_state; /* Current job state */
@@ -237,6 +238,7 @@ main(int argc, /* I - Number of command-line args */
ipp_attribute_t *printer_state; /* printer-state attribute */
ipp_attribute_t *printer_accepting; /* printer-is-accepting-jobs */
int create_job = 0, /* Does printer support Create-Job? */
+ get_job_attrs = 0, /* Does printer support Get-Job-Attributes? */
send_document = 0, /* Does printer support Send-Document? */
validate_job = 0; /* Does printer support Validate-Job? */
int copies, /* Number of copies for job */
@@ -1065,6 +1067,8 @@ main(int argc, /* I - Number of command-line args */
create_job = 1;
else if (operations_sup->values[i].integer == IPP_SEND_DOCUMENT)
send_document = 1;
+ else if (operations_sup->values[i].integer == IPP_GET_JOB_ATTRIBUTES)
+ get_job_attrs = 1;
}
if (!send_document)
@@ -1255,6 +1259,7 @@ main(int argc, /* I - Number of command-line args */
monitor.port = port;
monitor.version = version;
monitor.job_id = 0;
+ monitor.get_job_attrs = get_job_attrs;
monitor.encryption = cupsEncryption();
monitor.job_state = IPP_JOB_PENDING;
monitor.printer_state = IPP_PRINTER_IDLE;
@@ -1298,6 +1303,8 @@ main(int argc, /* I - Number of command-line args */
_cupsLangPrintFilter(stderr, "INFO", _("The printer is busy."));
sleep(10);
}
+ else if (ipp_status == IPP_DOCUMENT_FORMAT)
+ goto cleanup;
else if (ipp_status == IPP_FORBIDDEN ||
ipp_status == IPP_AUTHENTICATION_CANCELED)
{
@@ -1652,7 +1659,7 @@ main(int argc, /* I - Number of command-line args */
* Wait for the job to complete...
*/
- if (!job_id || !waitjob)
+ if (!job_id || !waitjob || !get_job_attrs)
continue;
_cupsLangPrintFilter(stderr, "INFO", _("Waiting for job to complete."));
@@ -1695,7 +1702,7 @@ main(int argc, /* I - Number of command-line args */
response = cupsDoRequest(http, request, resource);
ipp_status = cupsLastError();
- if (ipp_status == IPP_NOT_FOUND)
+ if (ipp_status == IPP_NOT_FOUND || ipp_status == IPP_NOT_POSSIBLE)
{
/*
* Job has gone away and/or the server has no job history...
@@ -1717,7 +1724,6 @@ main(int argc, /* I - Number of command-line args */
else
{
if (ipp_status != IPP_SERVICE_UNAVAILABLE &&
- ipp_status != IPP_NOT_POSSIBLE &&
ipp_status != IPP_PRINTER_BUSY)
{
ippDelete(response);
@@ -1865,12 +1871,17 @@ main(int argc, /* I - Number of command-line args */
return (CUPS_BACKEND_AUTH_REQUIRED);
else if (ipp_status == IPP_INTERNAL_ERROR)
return (CUPS_BACKEND_STOP);
- else if (ipp_status == IPP_DOCUMENT_FORMAT ||
- ipp_status == IPP_CONFLICT)
+ else if (ipp_status == IPP_CONFLICT)
return (CUPS_BACKEND_FAILED);
- else if (ipp_status == IPP_REQUEST_VALUE)
+ else if (ipp_status == IPP_REQUEST_VALUE ||
+ ipp_status == IPP_DOCUMENT_FORMAT)
{
- _cupsLangPrintFilter(stderr, "ERROR", _("Print job too large."));
+ if (ipp_status == IPP_REQUEST_VALUE)
+ _cupsLangPrintFilter(stderr, "ERROR", _("Print job too large."));
+ else
+ _cupsLangPrintFilter(stderr, "ERROR",
+ _("Printer cannot print supplied content."));
+
return (CUPS_BACKEND_CANCEL);
}
else if (ipp_status > IPP_OK_CONFLICT && ipp_status != IPP_ERROR_JOB_CANCELED)
@@ -2116,7 +2127,8 @@ monitor_printer(
* Check the status of the job itself...
*/
- job_op = monitor->job_id > 0 ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS;
+ job_op = (monitor->job_id > 0 && monitor->get_job_attrs) ?
+ IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS;
request = ippNewRequest(job_op);
request->request.op.version[0] = monitor->version / 10;
request->request.op.version[1] = monitor->version % 10;
@@ -2306,7 +2318,7 @@ new_request(
fprintf(stderr, "DEBUG: job-name=\"%s\"\n", title);
}
- if (format)
+ if (format && op != IPP_CREATE_JOB)
{
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
"document-format", NULL, format);
@@ -2314,7 +2326,7 @@ new_request(
}
#ifdef HAVE_LIBZ
- if (compression)
+ if (compression && op != IPP_CREATE_JOB)
{
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
"compression", NULL, compression);
@@ -2514,7 +2526,7 @@ new_request(
* When talking to another CUPS server, send all options...
*/
- cupsEncodeOptions(request, num_options, options);
+ cupsEncodeOptions2(request, num_options, options, IPP_TAG_JOB);
}
if (copies > 1)
@@ -3205,5 +3217,5 @@ update_reasons(ipp_attribute_t *attr, /* I - printer-state-reasons or NULL */
}
/*
- * End of "$Id: ipp.c 10452 2012-05-04 23:00:01Z mike $".
+ * End of "$Id: ipp.c 10509 2012-05-23 22:47:10Z mike $".
*/
diff --git a/backend/usb-libusb.c b/backend/usb-libusb.c
index e3a02be9..b9e40b25 100644
--- a/backend/usb-libusb.c
+++ b/backend/usb-libusb.c
@@ -1,5 +1,5 @@
/*
- * "$Id: usb-libusb.c 10267 2012-02-12 08:35:28Z mike $"
+ * "$Id: usb-libusb.c 10545 2012-07-16 17:16:46Z mike $"
*
* LIBUSB interface code for CUPS.
*
@@ -22,6 +22,9 @@
* 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
+ * quirks() - Get the known quirks of a given printer model
* 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,13 +63,15 @@ typedef struct usb_printer_s /**** USB Printer Data ****/
{
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
- attached? */
+ usblp_attached, /* "usblp" kernel module attached? */
+ opened_for_job; /* Set to 1 by print_device() */
+ unsigned int quirks; /* Quirks flags */
struct libusb_device_handle *handle; /* Open handle to device */
} usb_printer_t;
@@ -99,6 +104,55 @@ typedef struct usb_globals_s
int sidechannel_thread_done;
} usb_globals_t;
+/*
+ * Quirks: various printer quirks are handled by this table & its flags.
+ *
+ * This is copied from the usblp kernel module. So we can easily copy and paste
+ * new quirks from the module.
+ */
+
+struct quirk_printer_struct {
+ int vendorId;
+ int productId;
+ unsigned int quirks;
+};
+
+#define USBLP_QUIRK_BIDIR 0x1 /* reports bidir but requires
+ unidirectional mode (no INs/reads) */
+#define USBLP_QUIRK_USB_INIT 0x2 /* needs vendor USB init string */
+#define USBLP_QUIRK_BAD_CLASS 0x4 /* descriptor uses vendor-specific
+ Class or SubClass */
+#define USBLP_QUIRK_NO_REATTACH 0x8000 /* After printing we cannot re-attach
+ the usblp kernel module */
+
+static const struct quirk_printer_struct quirk_printers[] = {
+ { 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */
+ { 0x03f0, 0x0104, USBLP_QUIRK_BIDIR }, /* HP DeskJet 880C */
+ { 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */
+ { 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */
+ { 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */
+ { 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */
+ { 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */
+ { 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */
+ { 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */
+ { 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */
+ { 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */
+ { 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */
+ { 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */
+ { 0x0482, 0x0010, USBLP_QUIRK_BIDIR }, /* Kyocera Mita FS 820,
+ by zut <kernel@zut.de> */
+ { 0x04f9, 0x000d, USBLP_QUIRK_BIDIR |
+ USBLP_QUIRK_NO_REATTACH }, /* Brother Industries, Ltd
+ HL-1440 Laser Printer */
+ { 0x04b8, 0x0202, USBLP_QUIRK_BAD_CLASS }, /* Seiko Epson Receipt
+ Printer M129C */
+ { 0x067b, 0x2305, USBLP_QUIRK_BIDIR |
+ USBLP_QUIRK_NO_REATTACH },
+ /* Prolific Technology, Inc. PL2305 Parallel Port
+ (USB -> Parallel adapter) */
+ { 0, 0 }
+};
+
/*
* Globals...
@@ -124,6 +178,8 @@ static char *make_device_uri(usb_printer_t *printer,
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 unsigned int quirks(int vendor, int product);
static void *read_thread(void *reference);
static void *sidechannel_thread(void *reference);
static void soft_reset(void);
@@ -163,7 +219,8 @@ print_device(const char *uri, /* I - Device URI */
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 +229,9 @@ print_device(const char *uri, /* I - Device URI */
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 +247,7 @@ print_device(const char *uri, /* I - Device URI */
* 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",
@@ -195,6 +256,7 @@ print_device(const char *uri, /* I - Device URI */
}
g.print_fd = print_fd;
+ g.printer->opened_for_job = 1;
/*
* If we are printing data from a print driver on stdin, ignore SIGTERM
@@ -240,24 +302,61 @@ print_device(const char *uri, /* I - Device URI */
}
/*
- * 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);
+ /*
+ * Debug mode: If option "usb-no-reattach" is given, do not re-attach
+ * the usblp kernel module after the job has completed.
+ */
- if (pthread_create(&read_thread_id, NULL, read_thread, NULL))
+ val = cupsGetOption("usb-no-reattach", num_opts, opts);
+ if (val && strcasecmp(val, "no") && strcasecmp(val, "off") &&
+ strcasecmp(val, "false"))
{
- 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);
+ g.printer->usblp_attached = 0;
+ fprintf(stderr, "DEBUG: Forced not re-attaching the usblp kernel module "
+ "after the job via \"usb-no-reattach\" option.\n");
+ }
+
+ /*
+ * Get the read thread going...
+ */
+
+ if (g.printer->read_endp != -1)
+ {
+ 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 +614,54 @@ print_device(const char *uri, /* I - Device URI */
* 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);
+ g.read_thread_stop = 1;
- gettimeofday(&tv, NULL);
- cond_timeout.tv_sec = tv.tv_sec + WAIT_EOF_DELAY;
- cond_timeout.tv_nsec = tv.tv_usec * 1000;
+ pthread_mutex_lock(&g.read_thread_mutex);
- 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;
+ 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);
@@ -600,31 +703,86 @@ close_device(usb_printer_t *printer) /* I - Printer */
* to the device...
*/
- int number; /* Interface number */
+ int errcode; /* Return value of libusb function */
+ int number1, /* Interface number */
+ number2; /* Configuration number */
- libusb_get_device_descriptor (printer->device, &devdesc);
- libusb_get_config_descriptor (printer->device, printer->conf, &confptr);
- number = confptr->interface[printer->iface].
- altsetting[printer->altset].bInterfaceNumber;
- libusb_release_interface(printer->handle, number);
- if (number != 0)
- libusb_release_interface(printer->handle, 0);
+ errcode =
+ libusb_get_config_descriptor(printer->device, printer->conf, &confptr);
+ if (errcode >= 0)
+ {
+ number1 = confptr->interface[printer->iface].
+ altsetting[printer->altset].bInterfaceNumber;
+ libusb_release_interface(printer->handle, number1);
+
+ number2 = confptr->bConfigurationValue;
+
+ libusb_free_config_descriptor(confptr);
+
+ /*
+ * If we have changed the configuration from one valid configuration
+ * to another, restore the old one
+ */
+ if (printer->origconf > 0 && 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, number1) < 0)
+ {
+ errcode = libusb_get_device_descriptor (printer->device, &devdesc);
+ if (errcode < 0)
+ fprintf(stderr,
+ "DEBUG: Failed to re-attach \"usblp\" kernel module\n");
+ else
+ fprintf(stderr,
+ "DEBUG: Failed to re-attach \"usblp\" kernel module to "
+ "%04x:%04x\n", devdesc.idVendor, devdesc.idProduct);
+ }
+ }
+ else
+ fprintf(stderr,
+ "DEBUG: Failed to get configuration descriptor %d\n",
+ printer->conf);
/*
- * Re-attach "usblp" kernel module if it was attached before using this
- * device
+ * Reset the device to clean up after the job
*/
- if (printer->usblp_attached == 1)
+ if (printer->opened_for_job == 1)
{
- if (libusb_attach_kernel_driver(printer->handle, printer->iface) < 0)
+ if ((errcode = libusb_reset_device(printer->handle)) < 0)
fprintf(stderr,
- "DEBUG: Failed to re-attach \"usblp\" kernel module to "
- "%04x:%04x\n", devdesc.idVendor, devdesc.idProduct);
+ "DEBUG: Device reset failed, error code: %d\n",
+ errcode);
+ else
+ fprintf(stderr,
+ "DEBUG: Resetting printer.\n");
}
- libusb_free_config_descriptor(confptr);
-
/*
* Close the interface and return...
*/
@@ -694,15 +852,18 @@ find_device(usb_cb_t cb, /* I - Callback function */
* a printer...
*/
- libusb_get_device_descriptor (device, &devdesc);
+ if (libusb_get_device_descriptor(device, &devdesc) < 0)
+ continue;
if (!devdesc.bNumConfigurations || !devdesc.idVendor ||
!devdesc.idProduct)
continue;
+ printer.quirks = quirks(devdesc.idVendor, devdesc.idProduct);
+
for (conf = 0; conf < devdesc.bNumConfigurations; conf ++)
{
- if (libusb_get_config_descriptor (device, conf, &confptr) < 0)
+ if (libusb_get_config_descriptor(device, conf, &confptr) < 0)
continue;
for (iface = 0, ifaceptr = confptr->interface;
iface < confptr->bNumInterfaces;
@@ -724,13 +885,18 @@ find_device(usb_cb_t cb, /* I - Callback function */
* 1284.4 (packet mode) protocol as well.
*/
- if (altptr->bInterfaceClass != LIBUSB_CLASS_PRINTER ||
- altptr->bInterfaceSubClass != 1 ||
+ if (((altptr->bInterfaceClass != LIBUSB_CLASS_PRINTER ||
+ altptr->bInterfaceSubClass != 1) &&
+ ((printer.quirks & USBLP_QUIRK_BAD_CLASS) == 0)) ||
(altptr->bInterfaceProtocol != 1 && /* Unidirectional */
altptr->bInterfaceProtocol != 2) || /* Bidirectional */
altptr->bInterfaceProtocol < protocol)
continue;
+ if (printer.quirks & USBLP_QUIRK_BAD_CLASS)
+ fprintf(stderr, "DEBUG: Printer does not report class 7 and/or "
+ "subclass 1 but works as a printer anyway\n");
+
read_endp = -1;
write_endp = -1;
@@ -755,7 +921,10 @@ find_device(usb_cb_t cb, /* I - Callback function */
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;
}
}
@@ -773,16 +942,41 @@ find_device(usb_cb_t cb, /* I - Callback function */
make_device_uri(&printer, device_id, device_uri,
sizeof(device_uri));
+ fprintf(stderr, "DEBUG2: 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.quirks & USBLP_QUIRK_BIDIR)
+ {
+ printer.read_endp = -1;
+ fprintf(stderr, "DEBUG: Printer reports bi-di support "
+ "but in reality works only uni-directionally\n");
+ }
+ 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;
+ if (printer.quirks & USBLP_QUIRK_NO_REATTACH)
+ {
+ printer.usblp_attached = 0;
+ fprintf(stderr, "DEBUG: Printer does not like usblp "
+ "kernel module to be re-attached after job\n");
+ }
+ libusb_free_config_descriptor(confptr);
return (&printer);
}
@@ -1086,12 +1280,53 @@ open_device(usb_printer_t *printer, /* I - Printer */
* 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;
+ printer->opened_for_job = 0;
if (verbose)
fputs("STATE: +connecting-to-device\n", stderr);
+ if ((errcode = libusb_get_device_descriptor(printer->device, &devdesc)) < 0)
+ {
+ fprintf(stderr, "DEBUG: Failed to get device descriptor, code: %d\n",
+ errcode);
+ goto error;
+ }
+
+ /*
+ * Get the "usblp" kernel module out of the way. This backend only
+ * works without the module attached.
+ */
+
+ errcode = libusb_kernel_driver_active(printer->handle, printer->iface);
+ if (errcode == 0)
+ printer->usblp_attached = 0;
+ else if (errcode == 1)
+ {
+ printer->usblp_attached = 1;
+ if ((errcode =
+ libusb_detach_kernel_driver(printer->handle, printer->iface)) < 0)
+ {
+ fprintf(stderr, "DEBUG: Failed to detach \"usblp\" module from %04x:%04x\n",
+ devdesc.idVendor, devdesc.idProduct);
+ goto error;
+ }
+ }
+ else
+ {
+ printer->usblp_attached = 0;
+ fprintf(stderr, "DEBUG: Failed to check whether %04x:%04x has the \"usblp\" kernel module attached\n",
+ devdesc.idVendor, devdesc.idProduct);
+ goto error;
+ }
+
/*
* Set the desired configuration, but only if it needs changing. Some
* printers (e.g., Samsung) don't like libusb_set_configuration. It will
@@ -1106,12 +1341,22 @@ open_device(usb_printer_t *printer, /* I - Printer */
0, 0, (unsigned char *)&current, 1, 5000) < 0)
current = 0; /* Assume not configured */
- libusb_get_device_descriptor (printer->device, &devdesc);
- libusb_get_config_descriptor (printer->device, printer->conf, &confptr);
+ printer->origconf = current;
+
+ if ((errcode =
+ libusb_get_config_descriptor (printer->device, printer->conf, &confptr))
+ < 0)
+ {
+ fprintf(stderr, "DEBUG: Failed to get config descriptor for %04x:%04x\n",
+ devdesc.idVendor, devdesc.idProduct);
+ goto error;
+ }
number1 = confptr->bConfigurationValue;
if (number1 != current)
{
+ fprintf(stderr, "DEBUG: Switching USB device configuration: %d -> %d\n",
+ current, number1);
if ((errcode = libusb_set_configuration(printer->handle, number1)) < 0)
{
/*
@@ -1127,33 +1372,6 @@ open_device(usb_printer_t *printer, /* I - Printer */
}
/*
- * Get the "usblp" kernel module out of the way. This backend only
- * works without the module attached.
- */
-
- errcode = libusb_kernel_driver_active(printer->handle, printer->iface);
- if (errcode == 0)
- printer->usblp_attached = 0;
- else if (errcode == 1)
- {
- printer->usblp_attached = 1;
- if ((errcode =
- libusb_detach_kernel_driver(printer->handle, printer->iface)) < 0)
- {
- fprintf(stderr, "DEBUG: Failed to detach \"usblp\" module from %04x:%04x\n",
- devdesc.idVendor, devdesc.idProduct);
- goto error;
- }
- }
- else
- {
- printer->usblp_attached = 0;
- fprintf(stderr, "DEBUG: Failed to check whether %04x:%04x has the \"usblp\" kernel module attached\n",
- devdesc.idVendor, devdesc.idProduct);
- goto error;
- }
-
- /*
* Claim interfaces as needed...
*/
@@ -1163,11 +1381,13 @@ open_device(usb_printer_t *printer, /* I - Printer */
while ((errcode = libusb_claim_interface(printer->handle, number1)) < 0)
{
if (errcode != LIBUSB_ERROR_BUSY)
+ {
fprintf(stderr,
"DEBUG: Failed to claim interface %d for %04x:%04x: %s\n",
number1, devdesc.idVendor, devdesc.idProduct, strerror(errno));
- goto error;
+ goto error;
+ }
}
/*
@@ -1187,12 +1407,14 @@ open_device(usb_printer_t *printer, /* I - Printer */
< 0)
{
if (errcode != LIBUSB_ERROR_BUSY)
+ {
fprintf(stderr,
"DEBUG: Failed to set alternate interface %d for %04x:%04x: "
"%s\n",
number2, devdesc.idVendor, devdesc.idProduct, strerror(errno));
- goto error;
+ goto error;
+ }
}
}
@@ -1314,6 +1536,64 @@ print_cb(usb_printer_t *printer, /* I - Printer */
/*
+ * '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,
+ errcode;
+
+ 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);
+ if ((errcode = libusb_control_transfer(printer->handle,
+ LIBUSB_REQUEST_TYPE_CLASS |
+ LIBUSB_ENDPOINT_OUT |
+ LIBUSB_RECIPIENT_OTHER,
+ 2, 0, interface, NULL, 0, 5000)) < 0)
+ errcode = libusb_control_transfer(printer->handle,
+ LIBUSB_REQUEST_TYPE_CLASS |
+ LIBUSB_ENDPOINT_OUT |
+ LIBUSB_RECIPIENT_INTERFACE,
+ 2, 0, interface, NULL, 0, 5000);
+ return errcode;
+}
+
+
+/*
+ * 'quirks()' - Get the known quirks of a given printer model
+ */
+
+static unsigned int quirks(int vendor, int product)
+{
+ int i;
+
+ for (i = 0; quirk_printers[i].vendorId; i++)
+ {
+ if (vendor == quirk_printers[i].vendorId &&
+ product == quirk_printers[i].productId)
+ return quirk_printers[i].quirks;
+ }
+ return 0;
+}
+
+
+/*
* 'read_thread()' - Thread to read the backchannel data on.
*/
@@ -1587,7 +1867,7 @@ static void soft_reset(void)
* Send the reset...
*/
- libusb_reset_device (g.printer->handle);
+ printer_class_soft_reset(g.printer);
/*
* Release the I/O lock...
@@ -1601,6 +1881,6 @@ static void soft_reset(void)
/*
- * End of "$Id: usb-libusb.c 10267 2012-02-12 08:35:28Z mike $".
+ * End of "$Id: usb-libusb.c 10545 2012-07-16 17:16:46Z mike $".
*/