diff options
author | Didier Raboud <odyx@debian.org> | 2012-10-25 21:06:09 +0200 |
---|---|---|
committer | Didier Raboud <odyx@debian.org> | 2012-10-25 21:06:09 +0200 |
commit | a75966e33dbc3e3e096338fd332f515cb313b58a (patch) | |
tree | 55daa4cc36ac303f40a1b7491f21143bc849d386 /backend | |
parent | b1469ea9a3a5b5b652dcd733f7d419dd1fdfe844 (diff) | |
download | cups-a75966e33dbc3e3e096338fd332f515cb313b58a.tar.gz |
Imported Upstream version 1.5.4upstream/1.5.4
Diffstat (limited to 'backend')
-rw-r--r-- | backend/ipp.c | 40 | ||||
-rw-r--r-- | backend/usb-libusb.c | 488 |
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 *)¤t, 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 $". */ |