1diff --git a/backend/usb-oh.c b/backend/usb-oh.c 2new file mode 100644 3index 0000000..668ea73 4--- /dev/null 5+++ b/backend/usb-oh.c 6@@ -0,0 +1,1818 @@ 7+/* 8+ * Copyright (c) 2024 Huawei Device Co., Ltd. 9+ * Licensed under the Apache License, Version 2.0 (the "License"); 10+ * you may not use this file except in compliance with the License. 11+ * You may obtain a copy of the License at 12+ * 13+ * http://www.apache.org/licenses/LICENSE-2.0 14+ * 15+ * Unless required by applicable law or agreed to in writing, software 16+ * distributed under the License is distributed on an "AS IS" BASIS, 17+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18+ * See the License for the specific language governing permissions and 19+ * limitations under the License. 20+ */ 21+ 22+/* 23+ * OH USB interface code for CUPS. 24+ */ 25+ 26+/* 27+ * Include necessary headers. 28+ */ 29+ 30+#include "usb_manager.h" 31+#include <cups/cups-private.h> 32+#include <cups/ppd-private.h> 33+#include <cups/dir.h> 34+#include <pthread.h> 35+#include <sys/select.h> 36+#include <sys/types.h> 37+#include <sys/stat.h> 38+#include <sys/time.h> 39+#include <unistd.h> 40+ 41+/* 42+ * WAIT_EOF_DELAY is number of seconds we'll wait for responses from 43+ * the printer after we've finished sending all the data 44+ */ 45+ 46+#define WAIT_EOF 0 47+#define WAIT_EOF_DELAY 7 48+#define WAIT_SIDE_DELAY 3 49+ 50+/* 51+ * Quirks: various printer quirks are handled by this structure and its flags. 52+ * 53+ * The quirks table used to be compiled into the backend but is now loaded from 54+ * one or more files in the /usr/share/cups/usb directory. 55+ */ 56+ 57+#define USB_QUIRK_BLACKLIST 0x0001 /* Does not conform to the spec */ 58+#define USB_QUIRK_NO_REATTACH 0x0002 /* After printing we cannot re-attach 59+ the usblp kernel module */ 60+#define USB_QUIRK_SOFT_RESET 0x0004 /* After printing do a soft reset 61+ for clean-up */ 62+#define USB_QUIRK_UNIDIR 0x0008 /* Requires unidirectional mode */ 63+#define USB_QUIRK_USB_INIT 0x0010 /* Needs vendor USB init string */ 64+#define USB_QUIRK_VENDOR_CLASS 0x0020 /* Descriptor uses vendor-specific 65+ Class or SubClass */ 66+#define USB_QUIRK_DELAY_CLOSE 0x0040 /* Delay close */ 67+#define USB_QUIRK_WHITELIST 0x0000 /* no quirks */ 68+ 69+/* 70+ * Local types... 71+ */ 72+ 73+typedef struct usb_printer_s /**** USB Printer Data ****/ 74+{ 75+ ohusb_device_descriptor *device; /* Device info */ 76+ int conf, /* Configuration */ 77+ origconf, /* Original configuration */ 78+ iface, /* Interface */ 79+ altset, /* Alternate setting */ 80+ write_endp, /* Write endpoint */ 81+ read_endp, /* Read endpoint */ 82+ protocol, /* Protocol: 1 = Uni-di, 2 = Bi-di. */ 83+ usblp_attached, /* "usblp" kernel module attached? */ 84+ reset_after_job;/* Set to 1 by print_device() */ 85+ unsigned quirks; /* Quirks flags */ 86+ ohusb_pipe *pipe; /* Open pipe to device */ 87+} usb_printer_t; 88+ 89+typedef struct usb_quirk_s /* USB "quirk" information */ 90+{ 91+ int vendor_id, /* Affected vendor ID */ 92+ product_id; /* Affected product ID or 0 for all */ 93+ unsigned quirks; /* Quirks bitfield */ 94+} usb_quirk_t; 95+ 96+typedef int (*usb_cb_t)(usb_printer_t *, const char *, const char *, const void *); 97+ 98+typedef struct usb_globals_s /* Global USB printer information */ 99+{ 100+ usb_printer_t *printer; /* Printer */ 101+ 102+ pthread_mutex_t read_thread_mutex; 103+ pthread_cond_t read_thread_cond; 104+ int read_thread_stop; 105+ int read_thread_done; 106+ 107+ pthread_mutex_t readwrite_lock_mutex; 108+ pthread_cond_t readwrite_lock_cond; 109+ int readwrite_lock; 110+ 111+ int print_fd; /* File descriptor to print */ 112+ ssize_t print_bytes; /* Print bytes read */ 113+ 114+ int wait_eof; 115+ int drain_output; /* Drain all pending output */ 116+ int bidi_flag; /* 0=unidirectional, 1=bidirectional */ 117+ 118+ pthread_mutex_t sidechannel_thread_mutex; 119+ pthread_cond_t sidechannel_thread_cond; 120+ int sidechannel_thread_stop; 121+ int sidechannel_thread_done; 122+} usb_globals_t; 123+ 124+/* 125+ * Globals... 126+ */ 127+ 128+cups_array_t *all_quirks; /* Array of printer quirks */ 129+usb_globals_t g = { 0 }; /* Globals */ 130+ohusb_device_descriptor **all_list; /* List of connected USB devices */ 131+ 132+/* 133+ * Local functions... 134+ */ 135+ 136+static int close_device(usb_printer_t *printer); 137+static int compare_quirks(usb_quirk_t *a, usb_quirk_t *b); 138+static usb_printer_t *find_device(usb_cb_t cb, const void *data); 139+static unsigned find_quirks(int vendor_id, int product_id); 140+static int get_device_id(usb_printer_t *printer, char *buffer, size_t bufsize); 141+static int list_cb(usb_printer_t *printer, const char *device_uri, const char *device_id, const void *data); 142+static void load_quirks(void); 143+static char *make_device_uri(usb_printer_t *printer, const char *device_id, char *uri, size_t uri_size); 144+static int open_device(usb_printer_t *printer, int verbose); 145+static int print_cb(usb_printer_t *printer, const char *device_uri, const char *device_id, const void *data); 146+static void *read_thread(void *reference); 147+static void *sidechannel_thread(void *reference); 148+static void soft_reset(void); 149+static int soft_reset_printer(usb_printer_t *printer); 150+ 151+/* 152+ * 'list_devices()' - List the available printers. 153+ */ 154+ 155+void 156+list_devices(void) 157+{ 158+ load_quirks(); 159+ 160+ fputs("DEBUG: list_devices\n", stderr); 161+ find_device(list_cb, NULL); 162+ fputs("DEBUG: list_devices out\n", stderr); 163+} 164+ 165+int /* O - Exit status */ 166+print_device(const char *uri, /* I - Device URI */ 167+ const char *hostname, /* I - Hostname/manufacturer */ 168+ const char *resource, /* I - Resource/modelname */ 169+ char *options, /* I - Device options/serial number */ 170+ int print_fd, /* I - File descriptor to print */ 171+ int copies, /* I - Copies to print */ 172+ int argc, /* I - Number of command-line arguments (6 or 7) */ 173+ char *argv[]) /* I - Command-line arguments */ 174+{ 175+ int bytes; /* Bytes written */ 176+ ssize_t total_bytes; /* Total bytes written */ 177+ struct sigaction action; /* Actions for POSIX signals */ 178+ int status = CUPS_BACKEND_OK, /* Function results */ 179+ iostatus; /* Current IO status */ 180+ pthread_t read_thread_id, /* Read thread */ 181+ sidechannel_thread_id; /* Side-channel thread */ 182+ int have_sidechannel = 0, /* Was the side-channel thread started? */ 183+ have_backchannel = 0; /* Do we have a back channel? */ 184+ struct stat sidechannel_info; /* Side-channel file descriptor info */ 185+ unsigned char print_buffer[8192], /* Print data buffer */ 186+ *print_ptr; /* Pointer into print data buffer */ 187+ fd_set input_set; /* Input set for select() */ 188+ int nfds; /* Number of file descriptors */ 189+ struct timeval *timeout, /* Timeout pointer */ 190+ tv; /* Time value */ 191+ struct timespec cond_timeout; /* pthread condition timeout */ 192+ int num_opts; /* Number of options */ 193+ cups_option_t *opts; /* Options */ 194+ const char *val; /* Option value */ 195+ 196+ fputs("DEBUG: print_device\n", stderr); 197+ 198+ load_quirks(); 199+ 200+ /* 201+ * See if the side-channel descriptor is valid... 202+ */ 203+ 204+ have_sidechannel = !fstat(CUPS_SC_FD, &sidechannel_info) && 205+ S_ISSOCK(sidechannel_info.st_mode); 206+ 207+ g.wait_eof = WAIT_EOF; 208+ 209+ /* 210+ * Connect to the printer... 211+ */ 212+ 213+ fprintf(stderr, "DEBUG: Printing on printer with URI: %s\n", uri); 214+ while ((g.printer = find_device(print_cb, uri)) == NULL) 215+ { 216+ _cupsLangPrintFilter(stderr, "INFO", _("Waiting for printer to become available.")); 217+ sleep(5); 218+ } 219+ 220+ g.print_fd = print_fd; 221+ 222+ /* 223+ * Some devices need a reset after finishing a job, these devices are 224+ * marked with the USB_QUIRK_SOFT_RESET quirk. 225+ */ 226+ g.printer->reset_after_job = (g.printer->quirks & USB_QUIRK_SOFT_RESET ? 1 : 0); 227+ 228+ /* 229+ * If we are printing data from a print driver on stdin, ignore SIGTERM 230+ * so that the driver can finish out any page data, e.g. to eject the 231+ * current page. We only do this for stdin printing as otherwise there 232+ * is no way to cancel a raw print job... 233+ */ 234+ 235+ if (!print_fd) 236+ { 237+ memset(&action, 0, sizeof(action)); 238+ 239+ sigemptyset(&action.sa_mask); 240+ action.sa_handler = SIG_IGN; 241+ sigaction(SIGTERM, &action, NULL); 242+ } 243+ 244+ /* 245+ * Start the side channel thread if the descriptor is valid... 246+ */ 247+ 248+ pthread_mutex_init(&g.readwrite_lock_mutex, NULL); 249+ pthread_cond_init(&g.readwrite_lock_cond, NULL); 250+ g.readwrite_lock = 1; 251+ 252+ if (have_sidechannel) 253+ { 254+ g.sidechannel_thread_stop = 0; 255+ g.sidechannel_thread_done = 0; 256+ 257+ pthread_cond_init(&g.sidechannel_thread_cond, NULL); 258+ pthread_mutex_init(&g.sidechannel_thread_mutex, NULL); 259+ 260+ if (pthread_create(&sidechannel_thread_id, NULL, sidechannel_thread, NULL)) 261+ { 262+ fprintf(stderr, "DEBUG: Fatal USB error.\n"); 263+ _cupsLangPrintFilter(stderr, "ERROR", _("There was an unrecoverable USB error.")); 264+ fputs("DEBUG: Couldn't create side-channel thread.\n", stderr); 265+ close_device(g.printer); 266+ return (CUPS_BACKEND_STOP); 267+ } 268+ } 269+ 270+ /* 271+ * Debug mode: If option "usb-unidir" is given, always deactivate 272+ * backchannel 273+ */ 274+ 275+ num_opts = cupsParseOptions(argv[5], 0, &opts); 276+ val = cupsGetOption("usb-unidir", num_opts, opts); 277+ if (val && strcasecmp(val, "no") && strcasecmp(val, "off") && strcasecmp(val, "false")) 278+ { 279+ g.printer->read_endp = -1; 280+ fprintf(stderr, "DEBUG: Forced uni-directional communication " 281+ "via \"usb-unidir\" option.\n"); 282+ } 283+ 284+ /* 285+ * Debug mode: If option "usb-no-reattach" is given, do not re-attach 286+ * the usblp kernel module after the job has completed. 287+ */ 288+ 289+ val = cupsGetOption("usb-no-reattach", num_opts, opts); 290+ if (val && strcasecmp(val, "no") && strcasecmp(val, "off") && strcasecmp(val, "false")) 291+ { 292+ g.printer->usblp_attached = 0; 293+ fprintf(stderr, "DEBUG: Forced not re-attaching the usblp kernel module " 294+ "after the job via \"usb-no-reattach\" option.\n"); 295+ } 296+ 297+ /* 298+ * Get the read thread going... 299+ */ 300+ 301+ if (g.printer->read_endp != -1) 302+ { 303+ have_backchannel = 1; 304+ 305+ g.read_thread_stop = 0; 306+ g.read_thread_done = 0; 307+ 308+ pthread_cond_init(&g.read_thread_cond, NULL); 309+ pthread_mutex_init(&g.read_thread_mutex, NULL); 310+ 311+ if (pthread_create(&read_thread_id, NULL, read_thread, NULL)) 312+ { 313+ fprintf(stderr, "DEBUG: Fatal USB error.\n"); 314+ _cupsLangPrintFilter(stderr, "ERROR", _("There was an unrecoverable USB error.")); 315+ fputs("DEBUG: Couldn't create read thread.\n", stderr); 316+ close_device(g.printer); 317+ return (CUPS_BACKEND_STOP); 318+ } 319+ } 320+ else 321+ fprintf(stderr, "DEBUG: Uni-directional device/mode, back channel " 322+ "deactivated.\n"); 323+ 324+ /* 325+ * The main thread sends the print file... 326+ */ 327+ 328+ g.drain_output = 0; 329+ g.print_bytes = 0; 330+ total_bytes = 0; 331+ print_ptr = print_buffer; 332+ 333+ while (status == CUPS_BACKEND_OK && copies-- > 0) 334+ { 335+ _cupsLangPrintFilter(stderr, "INFO", _("Sending data to printer.")); 336+ 337+ if (print_fd != STDIN_FILENO) 338+ { 339+ fputs("PAGE: 1 1\n", stderr); 340+ lseek(print_fd, 0, SEEK_SET); 341+ } 342+ 343+ while (status == CUPS_BACKEND_OK) 344+ { 345+ FD_ZERO(&input_set); 346+ 347+ if (!g.print_bytes) 348+ FD_SET(print_fd, &input_set); 349+ 350+ /* 351+ * Calculate select timeout... 352+ * If we have data waiting to send timeout is 100ms. 353+ * else if we're draining print_fd timeout is 0. 354+ * else we're waiting forever... 355+ */ 356+ 357+ if (g.print_bytes) 358+ { 359+ tv.tv_sec = 0; 360+ tv.tv_usec = 100000; /* 100ms */ 361+ timeout = &tv; 362+ } 363+ else if (g.drain_output) 364+ { 365+ tv.tv_sec = 0; 366+ tv.tv_usec = 0; 367+ timeout = &tv; 368+ } 369+ else 370+ timeout = NULL; 371+ 372+ /* 373+ * I/O is unlocked around select... 374+ */ 375+ 376+ pthread_mutex_lock(&g.readwrite_lock_mutex); 377+ g.readwrite_lock = 0; 378+ pthread_cond_signal(&g.readwrite_lock_cond); 379+ pthread_mutex_unlock(&g.readwrite_lock_mutex); 380+ 381+ nfds = select(print_fd + 1, &input_set, NULL, NULL, timeout); 382+ 383+ /* 384+ * Reacquire the lock... 385+ */ 386+ 387+ pthread_mutex_lock(&g.readwrite_lock_mutex); 388+ while (g.readwrite_lock) 389+ pthread_cond_wait(&g.readwrite_lock_cond, &g.readwrite_lock_mutex); 390+ g.readwrite_lock = 1; 391+ pthread_mutex_unlock(&g.readwrite_lock_mutex); 392+ 393+ if (nfds < 0) 394+ { 395+ if (errno == EINTR && total_bytes == 0) 396+ { 397+ fputs("DEBUG: Received an interrupt before any bytes were " 398+ "written, aborting.\n", stderr); 399+ close_device(g.printer); 400+ return (CUPS_BACKEND_OK); 401+ } 402+ else if (errno != EAGAIN && errno != EINTR) 403+ { 404+ _cupsLangPrintFilter(stderr, "ERROR", _("Unable to read print data.")); 405+ perror("DEBUG: select"); 406+ close_device(g.printer); 407+ return (CUPS_BACKEND_FAILED); 408+ } 409+ } 410+ 411+ /* 412+ * If drain output has finished send a response... 413+ */ 414+ 415+ if (g.drain_output && !nfds && !g.print_bytes) 416+ { 417+ /* Send a response... */ 418+ cupsSideChannelWrite(CUPS_SC_CMD_DRAIN_OUTPUT, CUPS_SC_STATUS_OK, NULL, 0, 1.0); 419+ g.drain_output = 0; 420+ } 421+ 422+ /* 423+ * Check if we have print data ready... 424+ */ 425+ 426+ if (FD_ISSET(print_fd, &input_set)) 427+ { 428+ g.print_bytes = read(print_fd, print_buffer, sizeof(print_buffer)); 429+ 430+ if (g.print_bytes < 0) 431+ { 432+ /* 433+ * Read error - bail if we don't see EAGAIN or EINTR... 434+ */ 435+ 436+ if (errno != EAGAIN && errno != EINTR) 437+ { 438+ _cupsLangPrintFilter(stderr, "ERROR", _("Unable to read print data.")); 439+ perror("DEBUG: read"); 440+ close_device(g.printer); 441+ return (CUPS_BACKEND_FAILED); 442+ } 443+ 444+ g.print_bytes = 0; 445+ } 446+ else if (g.print_bytes == 0) 447+ { 448+ /* 449+ * End of file, break out of the loop... 450+ */ 451+ 452+ break; 453+ } 454+ 455+ print_ptr = print_buffer; 456+ 457+ fprintf(stderr, "DEBUG: Read %d bytes of print data...\n", (int)g.print_bytes); 458+ } 459+ 460+ if (g.print_bytes) 461+ { 462+ ohusb_transfer_pipe tpipe = { 463+ g.printer->iface, 464+ g.printer->write_endp 465+ }; 466+ iostatus = OH_BulkTransferWrite(g.printer->pipe, &tpipe, 467+ print_buffer, g.print_bytes, &bytes, 0); 468+ /* 469+ * Ignore timeout errors, but retain the number of bytes written to 470+ * avoid sending duplicate data... 471+ */ 472+ 473+ if (iostatus == OHUSB_ERROR_TIMEOUT) 474+ { 475+ fputs("DEBUG: Got USB transaction timeout during write.\n", stderr); 476+ iostatus = 0; 477+ } 478+ 479+ /* 480+ * Retry a write after an aborted write since we probably just got 481+ * SIGTERM... 482+ */ 483+ 484+ else if (iostatus == OHUSB_ERROR_NO_DEVICE) 485+ { 486+ fputs("DEBUG: Got USB return aborted during write.\n", stderr); 487+ 488+ iostatus = OH_BulkTransferWrite(g.printer->pipe, &tpipe, 489+ print_buffer, g.print_bytes, &bytes, 0); 490+ } 491+ 492+ if (iostatus) 493+ { 494+ /* 495+ * Write error - bail if we don't see an error we can retry... 496+ */ 497+ 498+ _cupsLangPrintFilter(stderr, "ERROR", _("Unable to send data to printer.")); 499+ fprintf(stderr, "DEBUG: ohusb write operation returned %x.\n", iostatus); 500+ 501+ status = CUPS_BACKEND_FAILED; 502+ break; 503+ } 504+ else if (bytes > 0) 505+ { 506+ fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n", (int)bytes); 507+ 508+ g.print_bytes -= bytes; 509+ print_ptr += bytes; 510+ total_bytes += bytes; 511+ } 512+ fprintf(stderr, "DEBUG: %d bytes left to write...\n", (int)g.print_bytes); 513+ } 514+ 515+ if (print_fd != 0 && status == CUPS_BACKEND_OK) 516+ fprintf(stderr, "DEBUG: Sending print file, " CUPS_LLFMT " bytes...\n", 517+ CUPS_LLCAST total_bytes); 518+ } 519+ } 520+ 521+ fprintf(stderr, "DEBUG: Sent " CUPS_LLFMT " bytes...\n", 522+ CUPS_LLCAST total_bytes); 523+ 524+ /* 525+ * Signal the side channel thread to exit... 526+ */ 527+ 528+ if (have_sidechannel) 529+ { 530+ close(CUPS_SC_FD); 531+ pthread_mutex_lock(&g.readwrite_lock_mutex); 532+ g.readwrite_lock = 0; 533+ pthread_cond_signal(&g.readwrite_lock_cond); 534+ pthread_mutex_unlock(&g.readwrite_lock_mutex); 535+ 536+ g.sidechannel_thread_stop = 1; 537+ pthread_mutex_lock(&g.sidechannel_thread_mutex); 538+ 539+ if (!g.sidechannel_thread_done) 540+ { 541+ gettimeofday(&tv, NULL); 542+ cond_timeout.tv_sec = tv.tv_sec + WAIT_SIDE_DELAY; 543+ cond_timeout.tv_nsec = tv.tv_usec * 1000; 544+ 545+ while (!g.sidechannel_thread_done) 546+ { 547+ if (pthread_cond_timedwait(&g.sidechannel_thread_cond, 548+ &g.sidechannel_thread_mutex, 549+ &cond_timeout) != 0) 550+ break; 551+ } 552+ } 553+ 554+ pthread_mutex_unlock(&g.sidechannel_thread_mutex); 555+ } 556+ 557+ /* 558+ * Signal the read thread to exit then wait 7 seconds for it to complete... 559+ */ 560+ 561+ if (have_backchannel) 562+ { 563+ g.read_thread_stop = 1; 564+ 565+ pthread_mutex_lock(&g.read_thread_mutex); 566+ 567+ if (!g.read_thread_done) 568+ { 569+ fputs("DEBUG: Waiting for read thread to exit...\n", stderr); 570+ 571+ gettimeofday(&tv, NULL); 572+ cond_timeout.tv_sec = tv.tv_sec + WAIT_EOF_DELAY; 573+ cond_timeout.tv_nsec = tv.tv_usec * 1000; 574+ 575+ while (!g.read_thread_done) 576+ { 577+ if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex, 578+ &cond_timeout) != 0) 579+ break; 580+ } 581+ 582+ /* 583+ * If it didn't exit abort the pending read and wait an additional 584+ * second... 585+ */ 586+ 587+ if (!g.read_thread_done) 588+ { 589+ fputs("DEBUG: Read thread still active, aborting the pending read...\n", stderr); 590+ 591+ g.wait_eof = 0; 592+ 593+ gettimeofday(&tv, NULL); 594+ cond_timeout.tv_sec = tv.tv_sec + 1; 595+ cond_timeout.tv_nsec = tv.tv_usec * 1000; 596+ 597+ while (!g.read_thread_done) 598+ { 599+ if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex, 600+ &cond_timeout) != 0) 601+ break; 602+ } 603+ } 604+ } 605+ 606+ pthread_mutex_unlock(&g.read_thread_mutex); 607+ } 608+ 609+ /* 610+ * Close the connection and input file and general clean up... 611+ */ 612+ 613+ if (g.printer->quirks & USB_QUIRK_DELAY_CLOSE) 614+ sleep(1); 615+ 616+ close_device(g.printer); 617+ 618+ fputs("DEBUG: print_device out\n", stderr); 619+ return (status); 620+} 621+ 622+/* 623+ * 'find_device()' - Find or enumerate USB printers. 624+ */ 625+ 626+static usb_printer_t * /* O - Found printer */ 627+find_device(usb_cb_t cb, /* I - Callback function */ 628+ const void *data) /* I - User data for callback */ 629+{ 630+ ohusb_device_descriptor *list = NULL; /* List of connected USB devices */ 631+ ohusb_device_descriptor *device = NULL; /* Current device */ 632+ ohusb_config_descriptor *confptr = NULL; /* Pointer to current configuration */ 633+ const ohusb_interface *ifaceptr = NULL; /* Pointer to current interface */ 634+ const ohusb_interface_descriptor *altptr = NULL; /* Pointer to current alternate setting */ 635+ const ohusb_endpoint_descriptor *endpptr = NULL; /* Pointer to current endpoint */ 636+ ssize_t numdevs, /* number of connected devices */ 637+ i = 0; 638+ uint8_t conf, /* Current configuration */ 639+ iface, /* Current interface */ 640+ altset, /* Current alternate setting */ 641+ protocol, /* Current protocol */ 642+ endp, /* Current endpoint */ 643+ read_endp, /* Current read endpoint */ 644+ write_endp; /* Current write endpoint */ 645+ char device_id[1024], /* IEEE-1284 device ID */ 646+ device_uri[1024]; /* Device URI */ 647+ static usb_printer_t printer; /* Current printer */ 648+ int32_t ret; 649+ 650+ /* 651+ * get ohusb devices... 652+ */ 653+ 654+ fputs("DEBUG: find_device\n", stderr); 655+ ret = OH_GetDevices(&list, &numdevs); 656+ if (ret != OHUSB_SUCCESS) { 657+ fprintf(stderr, "DEBUG: find_device OH_GetDevices fail\n"); 658+ return (NULL); 659+ } 660+ fprintf(stderr, "DEBUG: find_device OH_GetDevices numdevs=%d\n", (int)numdevs); 661+ 662+ /* 663+ * Then loop through the devices it found... 664+ */ 665+ 666+ if (numdevs > 0) 667+ for (i = 0; i < numdevs; i++) 668+ { 669+ device = list + i; 670+ 671+ /* 672+ * Ignore devices with no configuration data and anything that is not 673+ * a printer... 674+ */ 675+ 676+ if (device == NULL) 677+ continue; 678+ 679+ fprintf(stderr, "DEBUG: OH_GetDevices index=%zd, busNum=%d, devAddr=%d, idVendor=%d, idProduct=%d\n", 680+ i, device->busNum, device->devAddr, device->idVendor, device->idProduct); 681+ 682+ if (!device->bNumConfigurations || !device->idVendor || !device->idProduct) 683+ continue; 684+ 685+ printer.quirks = find_quirks(device->idVendor, device->idProduct); 686+ fprintf(stderr, "DEBUG: find_device quirks=%d\n", printer.quirks); 687+ 688+ /* 689+ * Ignore blacklisted printers... 690+ */ 691+ 692+ if (printer.quirks & USB_QUIRK_BLACKLIST) 693+ continue; 694+ 695+ for (conf = 0, confptr = device->config; conf < device->bNumConfigurations; conf ++, confptr ++) 696+ { 697+ if (confptr == NULL) 698+ continue; 699+ for (iface = 0, ifaceptr = confptr->interface; 700+ iface < confptr->bNumInterfaces; 701+ iface ++, ifaceptr ++) 702+ { 703+ /* 704+ * Some printers offer multiple interfaces... 705+ */ 706+ 707+ protocol = 0; 708+ if (ifaceptr == NULL) 709+ continue; 710+ 711+ for (altset = 0, altptr = ifaceptr->altsetting; 712+ altset < ifaceptr->num_altsetting; 713+ altset ++, altptr ++) 714+ { 715+ if (altptr == NULL) 716+ continue; 717+ /* 718+ * Currently we only support unidirectional and bidirectional 719+ * printers. Future versions of this code will support the 720+ * 1284.4 (packet mode) protocol as well. 721+ */ 722+ fprintf(stderr, "DEBUG: find_device class=%x, subclass=%x, protocol=%x\n", 723+ altptr->bInterfaceClass, altptr->bInterfaceSubClass, altptr->bInterfaceProtocol); 724+ if (((altptr->bInterfaceClass != OHUSB_CLASS_PRINTER || altptr->bInterfaceSubClass != 1) && 725+ ((printer.quirks & USB_QUIRK_VENDOR_CLASS) == 0)) || 726+ (altptr->bInterfaceProtocol != 1 && /* Unidirectional */ 727+ altptr->bInterfaceProtocol != 2) || /* Bidirectional */ 728+ altptr->bInterfaceProtocol < protocol) 729+ { 730+ fprintf(stderr, "DEBUG: Not a usb printer.\n"); 731+ continue; 732+ } 733+ 734+ if (printer.quirks & USB_QUIRK_VENDOR_CLASS) 735+ fprintf(stderr, "DEBUG: Printer does not report class 7 and/or " 736+ "subclass 1 but works as a printer anyway\n"); 737+ 738+ read_endp = 0xff; 739+ write_endp = 0xff; 740+ 741+ for (endp = 0, endpptr = altptr->endpoint; 742+ endp < altptr->bNumEndpoints; 743+ endp ++, endpptr ++) 744+ { 745+ if ((endpptr->bmAttributes & OHUSB_TRANSFER_TYPE_MASK) == OHUSB_TRANSFER_TYPE_BULK) 746+ { 747+ if (endpptr->bEndpointAddress & OHUSB_ENDPOINT_DIR_MASK) 748+ read_endp = endp; 749+ else 750+ write_endp = endp; 751+ } 752+ } 753+ 754+ if (write_endp != 0xff) 755+ { 756+ /* 757+ * Save the best match so far... 758+ */ 759+ 760+ protocol = altptr->bInterfaceProtocol; 761+ printer.altset = altset; 762+ printer.write_endp = write_endp; 763+ if (protocol > 1) 764+ printer.read_endp = read_endp; 765+ else 766+ printer.read_endp = -1; 767+ } 768+ } 769+ 770+ if (protocol > 0) 771+ { 772+ printer.device = device; 773+ printer.conf = conf; 774+ printer.iface = iface; 775+ printer.protocol = protocol; 776+ printer.pipe = NULL; 777+ 778+ if (!open_device(&printer, data != NULL)) 779+ { 780+ get_device_id(&printer, device_id, sizeof(device_id)); 781+ make_device_uri(&printer, device_id, device_uri, sizeof(device_uri)); 782+ 783+ fprintf(stderr, "DEBUG2: Printer found with device ID: %s " 784+ "Device URI: %s\n", 785+ device_id, device_uri); 786+ 787+ if ((*cb)(&printer, device_uri, device_id, data)) 788+ { 789+ fprintf(stderr, "DEBUG: Device protocol: %d\n", printer.protocol); 790+ if (printer.quirks & USB_QUIRK_UNIDIR) 791+ { 792+ printer.read_endp = -1; 793+ fprintf(stderr, "DEBUG: Printer reports bi-di support " 794+ "but in reality works only uni-directionally\n"); 795+ } 796+ if (printer.read_endp != -1) 797+ { 798+ printer.read_endp = confptr->interface[printer.iface]. 799+ altsetting[printer.altset]. 800+ endpoint[printer.read_endp]. 801+ bEndpointAddress; 802+ } 803+ else 804+ fprintf(stderr, "DEBUG: Uni-directional USB communication " 805+ "only!\n"); 806+ printer.write_endp = confptr->interface[printer.iface]. 807+ altsetting[printer.altset]. 808+ endpoint[printer.write_endp]. 809+ bEndpointAddress; 810+ if (printer.quirks & USB_QUIRK_NO_REATTACH) 811+ { 812+ printer.usblp_attached = 0; 813+ fprintf(stderr, "DEBUG: Printer does not like usblp " 814+ "kernel module to be re-attached after job\n"); 815+ } 816+ return (&printer); 817+ } 818+ 819+ close_device(&printer); 820+ } 821+ } 822+ } 823+ } 824+ } 825+ 826+ fputs("DEBUG: find_device out\n", stderr); 827+ return (NULL); 828+} 829+ 830+/* 831+ * 'open_device()' - Open a connection to the USB printer. 832+ */ 833+ 834+static int /* O - 0 on success, -1 on error */ 835+open_device(usb_printer_t *printer, /* I - Printer */ 836+ int verbose) /* I - Update connecting-to-device state? */ 837+{ 838+ ohusb_config_descriptor confptr; 839+ /* Pointer to current configuration */ 840+ int number1 = -1, /* Configuration/interface/altset */ 841+ number2 = -1, /* numbers */ 842+ errcode = 0; 843+ char current; /* Current configuration */ 844+ 845+ fprintf(stderr, "DEBUG: open_device\n"); 846+ 847+ /* 848+ * Return immediately if we are already connected... 849+ */ 850+ 851+ if (printer->pipe) 852+ return (0); 853+ 854+ /* 855+ * Try opening the printer... 856+ */ 857+ 858+ if ((errcode = OH_OpenDevice(printer->device, &(printer->pipe))) < 0) 859+ { 860+ fprintf(stderr, "DEBUG: Failed to open device, code: %d\n", errcode); 861+ return (-1); 862+ } 863+ fprintf(stderr, "DEBUG: OH_OpenDevice success busNum=%d, devAddr=%d\n", 864+ printer->pipe->busNum, printer->pipe->devAddr); 865+ 866+ printer->usblp_attached = 0; 867+ printer->reset_after_job = 0; 868+ 869+ if (verbose) 870+ fputs("STATE: +connecting-to-device\n", stderr); 871+ if (printer->device == NULL) 872+ { 873+ fprintf(stderr, "DEBUG: Failed to get device descriptor, code: %d\n", errcode); 874+ goto error; 875+ } 876+ 877+ /* 878+ * Set the desired configuration, but only if it needs changing. Some 879+ * printers (e.g., Samsung) don't like OH_SetConfiguration. It will 880+ * succeed, but the following print job is sometimes silently lost by the 881+ * printer. 882+ */ 883+ 884+ ohusb_control_transfer_parameter ctrlParam = { 885+ OHUSB_REQUEST_TYPE_STANDARD | OHUSB_ENDPOINT_IN | OHUSB_RECIPIENT_DEVICE, 886+ 8, 0, 0, 5000 887+ }; 888+ 889+ if (OH_ControlTransferRead(printer->pipe, &ctrlParam, (unsigned char *)¤t, 1) < 0) 890+ { 891+ current = 0; /* Assume not configured */ 892+ } 893+ 894+ printer->origconf = current; 895+ fprintf(stderr, "DEBUG: open_device OH_ControlTransferRead current = %c, printer->origconf = %d\n", 896+ current, printer->origconf); 897+ 898+ confptr = printer->device->config[printer->conf]; 899+ number1 = confptr.iConfiguration; 900+ 901+ if (number1 != current) 902+ { 903+ fprintf(stderr, "DEBUG: Switching USB device configuration: %d -> %d\n", 904+ current, number1); 905+ if ((errcode = OH_SetConfiguration(printer->pipe, number1)) < 0) 906+ { 907+ /* 908+ * If the set fails, chances are that the printer only supports a 909+ * single configuration. Technically these printers don't conform to 910+ * the USB printer specification, but otherwise they'll work... 911+ */ 912+ 913+ if (errcode != OHUSB_ERROR_BUSY) 914+ fprintf(stderr, "DEBUG: Failed to set configuration %d for %04x:%04x\n", 915+ number1, printer->device->idVendor, printer->device->idProduct); 916+ } 917+ } 918+ 919+ /* 920+ * Claim interfaces as needed... 921+ */ 922+ 923+ number1 = confptr.interface[printer->iface].altsetting[printer->altset].bInterfaceNumber; 924+ 925+ if ((errcode = OH_ClaimInterface(printer->pipe, number1, true)) < 0) 926+ { 927+ fprintf(stderr, 928+ "DEBUG: Failed to claim interface %d for %04x:%04x: %s\n", 929+ number1, printer->device->idVendor, printer->device->idProduct, strerror(errno)); 930+ 931+ goto error; 932+ } 933+ 934+ /* 935+ * Set alternate setting, but only if there is more than one option. Some 936+ * printers (e.g., Samsung) don't like usb_set_altinterface. 937+ */ 938+ 939+ if (confptr.interface[printer->iface].num_altsetting > 1) 940+ { 941+ number1 = confptr.interface[printer->iface]. 942+ altsetting[printer->altset].bInterfaceNumber; 943+ number2 = confptr.interface[printer->iface]. 944+ altsetting[printer->altset].bAlternateSetting; 945+ while ((errcode = OH_SetInterface(printer->pipe, number1, number2)) < 0) 946+ { 947+ if (errcode != OHUSB_ERROR_BUSY) 948+ { 949+ fprintf(stderr, 950+ "DEBUG: Failed to set alternate interface %d for %04x:%04x: " 951+ "%s\n", 952+ number2, printer->device->idVendor, printer->device->idProduct, strerror(errno)); 953+ 954+ goto error; 955+ } 956+ } 957+ } 958+ 959+ if (verbose) 960+ fputs("STATE: -connecting-to-device\n", stderr); 961+ 962+ return (0); 963+ 964+ /* 965+ * If we get here, there was a hard error... 966+ */ 967+ 968+ error: 969+ 970+ if (verbose) 971+ fputs("STATE: -connecting-to-device\n", stderr); 972+ 973+ OH_CloseDevice(printer->pipe); 974+ printer->pipe = NULL; 975+ 976+ return (-1); 977+} 978+ 979+/* 980+ * 'get_device_id()' - Get the IEEE-1284 device ID for the printer. 981+ */ 982+ 983+static int /* O - 0 on success, -1 on error */ 984+get_device_id(usb_printer_t *printer, /* I - Printer */ 985+ char *buffer, /* I - String buffer */ 986+ size_t bufsize) /* I - Number of bytes in buffer */ 987+{ 988+ fprintf(stderr, "DEBUG: get_device_id\n"); 989+ 990+ int length; /* Length of device ID */ 991+ 992+ ohusb_control_transfer_parameter ctrlParam = { 993+ OHUSB_REQUEST_TYPE_CLASS | OHUSB_ENDPOINT_IN | OHUSB_RECIPIENT_INTERFACE, 994+ 0, printer->conf, (printer->iface << 8) | printer->altset, 5000 995+ }; 996+ 997+ if (OH_ControlTransferRead(printer->pipe, &ctrlParam, (unsigned char *)buffer, bufsize) < 0) 998+ { 999+ *buffer = '\0'; 1000+ return (-1); 1001+ } 1002+ 1003+ /* 1004+ * Extract the length of the device ID string from the first two 1005+ * bytes. The 1284 spec says the length is stored MSB first... 1006+ */ 1007+ 1008+ length = (int)((((unsigned)buffer[0] & 255) << 8) | ((unsigned)buffer[1] & 255)); 1009+ 1010+ /* 1011+ * Check to see if the length is larger than our buffer or less than 14 bytes 1012+ * (the minimum valid device ID is "MFG:x;MDL:y;" with 2 bytes for the length). 1013+ * 1014+ * If the length is out-of-range, assume that the vendor incorrectly 1015+ * implemented the 1284 spec and re-read the length as LSB first,.. 1016+ */ 1017+ 1018+ if (length > bufsize || length < 14) 1019+ length = (int)((((unsigned)buffer[1] & 255) << 8) | ((unsigned)buffer[0] & 255)); 1020+ 1021+ if (length > bufsize) 1022+ length = bufsize; 1023+ 1024+ if (length < 14) 1025+ { 1026+ /* 1027+ * Invalid device ID, clear it! 1028+ */ 1029+ 1030+ *buffer = '\0'; 1031+ fprintf(stderr, "DEBUG: get_device_id Invalid device ID\n"); 1032+ return (-1); 1033+ } 1034+ 1035+ length -= 2; 1036+ fprintf(stderr, "DEBUG: get_device_id length = %d\n", length); 1037+ 1038+ /* 1039+ * Copy the device ID text to the beginning of the buffer and 1040+ * nul-terminate. 1041+ */ 1042+ 1043+ memmove(buffer, buffer + 2, (size_t)length); 1044+ buffer[length] = '\0'; 1045+ 1046+ return (0); 1047+} 1048+ 1049+/* 1050+ * 'make_device_uri()' - Create a device URI for a USB printer. 1051+ */ 1052+ 1053+static char * /* O - Device URI */ 1054+make_device_uri( 1055+ usb_printer_t *printer, /* I - Printer */ 1056+ const char *device_id, /* I - IEEE-1284 device ID */ 1057+ char *uri, /* I - Device URI buffer */ 1058+ size_t uri_size) /* I - Size of device URI buffer */ 1059+{ 1060+ char options[1024]; /* Device URI options */ 1061+ int num_values; /* Number of 1284 parameters */ 1062+ cups_option_t *values; /* 1284 parameters */ 1063+ const char *mfg, /* Manufacturer */ 1064+ *mdl, /* Model */ 1065+ *des = NULL, /* Description */ 1066+ *sern = NULL; /* Serial number */ 1067+ size_t mfglen; /* Length of manufacturer string */ 1068+ char tempmdl[256], /* Temporary model string */ 1069+ tempmfg[256], /* Temporary manufacturer string */ 1070+ tempsern[256], /* Temporary serial number string */ 1071+ *tempptr; /* Pointer into temp string */ 1072+ 1073+ fprintf(stderr, "DEBUG: make_device_uri\n"); 1074+ 1075+ /* 1076+ * Get the make, model, and serial numbers... 1077+ */ 1078+ 1079+ num_values = _cupsGet1284Values(device_id, &values); 1080+ 1081+ if (printer->device != NULL && printer->device->iSerialNumber) 1082+ { 1083+ // Try getting the serial number from the device itself... 1084+ int length = OH_GetStringDescriptor(printer->pipe, printer->device->iSerialNumber, (unsigned char *)tempsern, sizeof(tempsern) - 1); 1085+ if (length > 0) 1086+ { 1087+ tempsern[length] = '\0'; 1088+ sern = tempsern; 1089+ } 1090+ else 1091+ fputs("DEBUG2: iSerialNumber could not be read.\n", stderr); 1092+ } 1093+ else 1094+ fputs("DEBUG2: iSerialNumber is not present.\n", stderr); 1095+ 1096+ if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL) 1097+ { 1098+ if ((mfg = cupsGetOption("MFG", num_values, values)) == NULL && printer->device->iManufacturer) 1099+ { 1100+ int length = OH_GetStringDescriptor(printer->pipe, printer->device->iManufacturer, (unsigned char *)tempmfg, sizeof(tempmfg) - 1); 1101+ if (length > 0) 1102+ { 1103+ tempmfg[length] = '\0'; 1104+ mfg = tempmfg; 1105+ } 1106+ } 1107+ } 1108+ 1109+ if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL) 1110+ { 1111+ if ((mdl = cupsGetOption("MDL", num_values, values)) == NULL && printer->device->iProduct) 1112+ { 1113+ int length = OH_GetStringDescriptor(printer->pipe, printer->device->iProduct, (unsigned char *)tempmdl, sizeof(tempmdl) - 1); 1114+ if (length > 0) 1115+ { 1116+ tempmdl[length] = '\0'; 1117+ mdl = tempmdl; 1118+ } 1119+ } 1120+ } 1121+ 1122+ /* 1123+ * To maintain compatibility with the original character device backend on 1124+ * Linux and *BSD, map manufacturer names... 1125+ */ 1126+ 1127+ if (mfg) 1128+ { 1129+ if (!_cups_strcasecmp(mfg, "Hewlett-Packard")) 1130+ mfg = "HP"; 1131+ else if (!_cups_strcasecmp(mfg, "Lexmark International")) 1132+ mfg = "Lexmark"; 1133+ } 1134+ else 1135+ { 1136+ /* 1137+ * No manufacturer? Use the model string or description... 1138+ */ 1139+ 1140+ if (mdl) 1141+ _ppdNormalizeMakeAndModel(mdl, tempmfg, sizeof(tempmfg)); 1142+ else if ((des = cupsGetOption("DESCRIPTION", num_values, values)) != NULL || 1143+ (des = cupsGetOption("DES", num_values, values)) != NULL) 1144+ _ppdNormalizeMakeAndModel(des, tempmfg, sizeof(tempmfg)); 1145+ else 1146+ strlcpy(tempmfg, "Unknown", sizeof(tempmfg)); 1147+ 1148+ if ((tempptr = strchr(tempmfg, ' ')) != NULL) 1149+ *tempptr = '\0'; 1150+ 1151+ mfg = tempmfg; 1152+ } 1153+ 1154+ if (!mdl) 1155+ { 1156+ /* 1157+ * No model? Use description... 1158+ */ 1159+ if (des) 1160+ mdl = des; /* We remove the manufacturer name below */ 1161+ else if (!strncasecmp(mfg, "Unknown", 7)) 1162+ mdl = "Printer"; 1163+ else 1164+ mdl = "Unknown Model"; 1165+ } 1166+ 1167+ mfglen = strlen(mfg); 1168+ 1169+ if (!strncasecmp(mdl, mfg, mfglen) && _cups_isspace(mdl[mfglen])) 1170+ { 1171+ mdl += mfglen + 1; 1172+ 1173+ while (_cups_isspace(*mdl)) 1174+ mdl ++; 1175+ } 1176+ 1177+ /* 1178+ * Generate the device URI from the manufacturer, model, serial number, 1179+ * and interface number... 1180+ */ 1181+ 1182+ if (sern) 1183+ { 1184+ if (printer->iface > 0) 1185+ snprintf(options, sizeof(options), "?serial=%s&interface=%d", sern, printer->iface); 1186+ else 1187+ snprintf(options, sizeof(options), "?serial=%s", sern); 1188+ } 1189+ else if (printer->iface > 0) 1190+ snprintf(options, sizeof(options), "?interface=%d", printer->iface); 1191+ else 1192+ options[0] = '\0'; 1193+ 1194+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, uri_size, "usb", NULL, mfg, 0, "/%s%s", mdl, options); 1195+ 1196+ fprintf(stderr, "DEBUG2: make_device_uri sern=\"%s\", mfg=\"%s\", mdl=\"%s\"\n", sern, mfg, mdl); 1197+ 1198+ cupsFreeOptions(num_values, values); 1199+ 1200+ return (uri); 1201+} 1202+ 1203+/* 1204+ * 'close_device()' - Close the connection to the USB printer. 1205+ */ 1206+ 1207+static int /* I - 0 on success, -1 on failure */ 1208+close_device(usb_printer_t *printer) /* I - Printer */ 1209+{ 1210+ ohusb_config_descriptor confptr; /* Pointer to current configuration */ 1211+ 1212+ if (printer->pipe) 1213+ { 1214+ /* 1215+ * Release interfaces before closing so that we know all data is written 1216+ * to the device... 1217+ */ 1218+ 1219+ int errcode; /* Return value of ohusb function */ 1220+ int number1, /* Interface number */ 1221+ number2; /* Configuration number */ 1222+ 1223+ if (printer->device != NULL && printer->device->config != NULL) 1224+ { 1225+ confptr = printer->device->config[printer->conf]; 1226+ number1 = confptr.interface[printer->iface]. 1227+ altsetting[printer->altset].bInterfaceNumber; 1228+ OH_ReleaseInterface(printer->pipe, number1); 1229+ 1230+ number2 = confptr.iConfiguration; 1231+ 1232+ /* 1233+ * If we have changed the configuration from one valid configuration 1234+ * to another, restore the old one 1235+ */ 1236+ if (printer->origconf > 0 && printer->origconf != number2) 1237+ { 1238+ fprintf(stderr, "DEBUG: Restoring USB device configuration: %d -> %d\n", 1239+ number2, printer->origconf); 1240+ if ((errcode = OH_SetConfiguration(printer->pipe, printer->origconf)) < 0) 1241+ { 1242+ fprintf(stderr, 1243+ "DEBUG: Failed to set configuration %d for %04x:%04x\n", 1244+ printer->origconf, printer->device->idVendor, printer->device->idProduct); 1245+ } 1246+ } 1247+ } 1248+ else 1249+ fprintf(stderr, 1250+ "DEBUG: Failed to get configuration descriptor %d\n", 1251+ printer->conf); 1252+ 1253+ /* 1254+ * Close the interface and return... 1255+ */ 1256+ 1257+ if (OH_CloseDevice(printer->pipe) == OHUSB_SUCCESS) 1258+ printer->pipe = NULL; 1259+ } 1260+ 1261+ return (0); 1262+} 1263+ 1264+/* 1265+ * 'read_thread()' - Thread to read the backchannel data on. 1266+ */ 1267+ 1268+static void *read_thread(void *reference) 1269+{ 1270+ unsigned char readbuffer[512]; 1271+ int rbytes; 1272+ int readstatus; 1273+ ohusb_transfer_pipe tpipe = { 1274+ g.printer->iface, 1275+ g.printer->read_endp 1276+ }; 1277+ 1278+ 1279+ (void)reference; 1280+ 1281+ do 1282+ { 1283+ /* 1284+ * Try reading from the OUT (to host) endpoint... 1285+ */ 1286+ 1287+ rbytes = sizeof(readbuffer); 1288+ readstatus = OH_BulkTransferRead(g.printer->pipe, 1289+ &tpipe, readbuffer, rbytes, &rbytes); 1290+ if (readstatus == OHUSB_SUCCESS && rbytes > 0) 1291+ { 1292+ fprintf(stderr, "DEBUG: Read %d bytes of back-channel data...\n", (int)rbytes); 1293+ cupsBackChannelWrite((const char *)readbuffer, (size_t)rbytes, 1.0); 1294+ } 1295+ else 1296+ fprintf(stderr, "DEBUG: Got USB transaction error during read, errorcode=%d\n", readstatus); 1297+ 1298+ /* 1299+ * Make sure this loop executes no more than once every 250 miliseconds... 1300+ */ 1301+ 1302+ if ((readstatus != OHUSB_SUCCESS || rbytes == 0) && (g.wait_eof || !g.read_thread_stop)) 1303+ usleep(250000); 1304+ } 1305+ while (g.wait_eof || !g.read_thread_stop); 1306+ 1307+ /* 1308+ * Let the main thread know that we have completed the read thread... 1309+ */ 1310+ 1311+ pthread_mutex_lock(&g.read_thread_mutex); 1312+ g.read_thread_done = 1; 1313+ pthread_cond_signal(&g.read_thread_cond); 1314+ pthread_mutex_unlock(&g.read_thread_mutex); 1315+ 1316+ return (NULL); 1317+} 1318+ 1319+/* 1320+ * 'sidechannel_thread()' - Handle side-channel requests. 1321+ */ 1322+ 1323+static void* 1324+sidechannel_thread(void *reference) 1325+{ 1326+ cups_sc_command_t command; /* Request command */ 1327+ cups_sc_status_t status; /* Request/response status */ 1328+ char data[2048]; /* Request/response data */ 1329+ int datalen; /* Request/response data size */ 1330+ 1331+ 1332+ (void)reference; 1333+ 1334+ do 1335+ { 1336+ datalen = sizeof(data); 1337+ 1338+ if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0)) 1339+ { 1340+ if (status == CUPS_SC_STATUS_TIMEOUT) 1341+ continue; 1342+ else 1343+ break; 1344+ } 1345+ 1346+ switch (command) 1347+ { 1348+ case CUPS_SC_CMD_SOFT_RESET: /* Do a soft reset */ 1349+ fputs("DEBUG: CUPS_SC_CMD_SOFT_RESET received from driver...\n", stderr); 1350+ 1351+ soft_reset(); 1352+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, NULL, 0, 1.0); 1353+ fputs("DEBUG: Returning status CUPS_STATUS_OK with no bytes...\n", 1354+ stderr); 1355+ break; 1356+ 1357+ case CUPS_SC_CMD_DRAIN_OUTPUT: /* Drain all pending output */ 1358+ fputs("DEBUG: CUPS_SC_CMD_DRAIN_OUTPUT received from driver...\n", stderr); 1359+ 1360+ g.drain_output = 1; 1361+ break; 1362+ 1363+ case CUPS_SC_CMD_GET_BIDI: /* Is the connection bidirectional? */ 1364+ fputs("DEBUG: CUPS_SC_CMD_GET_BIDI received from driver...\n", stderr); 1365+ 1366+ data[0] = (g.printer->protocol >= 2 ? 1 : 0); 1367+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0); 1368+ 1369+ fprintf(stderr, 1370+ "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n", 1371+ data[0]); 1372+ break; 1373+ 1374+ case CUPS_SC_CMD_GET_DEVICE_ID: /* Return IEEE-1284 device ID */ 1375+ fputs("DEBUG: CUPS_SC_CMD_GET_DEVICE_ID received from driver...\n", stderr); 1376+ 1377+ datalen = sizeof(data); 1378+ if (get_device_id(g.printer, data, sizeof(data))) 1379+ { 1380+ status = CUPS_SC_STATUS_IO_ERROR; 1381+ datalen = 0; 1382+ } 1383+ else 1384+ { 1385+ status = CUPS_SC_STATUS_OK; 1386+ datalen = strlen(data); 1387+ } 1388+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, datalen, 1.0); 1389+ 1390+ if (datalen < sizeof(data)) 1391+ data[datalen] = '\0'; 1392+ else 1393+ data[sizeof(data) - 1] = '\0'; 1394+ 1395+ fprintf(stderr, 1396+ "DEBUG: Returning CUPS_SC_STATUS_OK with %d bytes (%s)...\n", 1397+ datalen, data); 1398+ break; 1399+ 1400+ case CUPS_SC_CMD_GET_STATE: /* Return device state */ 1401+ fputs("DEBUG: CUPS_SC_CMD_GET_STATE received from driver...\n", stderr); 1402+ 1403+ data[0] = CUPS_SC_STATE_ONLINE; 1404+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0); 1405+ 1406+ fprintf(stderr, 1407+ "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n", 1408+ data[0]); 1409+ break; 1410+ 1411+ case CUPS_SC_CMD_GET_CONNECTED: /* Return whether device is 1412+ connected */ 1413+ fputs("DEBUG: CUPS_SC_CMD_GET_CONNECTED received from driver...\n", stderr); 1414+ 1415+ data[0] = (g.printer->device ? 1 : 0); 1416+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0); 1417+ 1418+ fprintf(stderr, 1419+ "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n", 1420+ data[0]); 1421+ break; 1422+ 1423+ default: 1424+ fprintf(stderr, "DEBUG: Unknown side-channel command (%d) received " 1425+ "from driver...\n", command); 1426+ 1427+ cupsSideChannelWrite(command, CUPS_SC_STATUS_NOT_IMPLEMENTED, NULL, 0, 1.0); 1428+ 1429+ fputs("DEBUG: Returned CUPS_SC_STATUS_NOT_IMPLEMENTED with no bytes...\n", stderr); 1430+ break; 1431+ } 1432+ } 1433+ while (!g.sidechannel_thread_stop); 1434+ 1435+ pthread_mutex_lock(&g.sidechannel_thread_mutex); 1436+ g.sidechannel_thread_done = 1; 1437+ pthread_cond_signal(&g.sidechannel_thread_cond); 1438+ pthread_mutex_unlock(&g.sidechannel_thread_mutex); 1439+ 1440+ return (NULL); 1441+} 1442+ 1443+/* 1444+ * 'load_quirks()' - Load all quirks files in the /usr/share/cups/usb directory. 1445+ */ 1446+ 1447+static void 1448+load_quirks(void) 1449+{ 1450+ const char *datadir; /* CUPS_DATADIR environment variable */ 1451+ char filename[1024], /* Filename */ 1452+ line[1024]; /* Line from file */ 1453+ cups_dir_t *dir; /* Directory */ 1454+ cups_dentry_t *dent; /* Directory entry */ 1455+ cups_file_t *fp; /* Quirks file */ 1456+ usb_quirk_t *quirk; /* New quirk */ 1457+ 1458+ 1459+ all_quirks = cupsArrayNew((cups_array_func_t)compare_quirks, NULL); 1460+ 1461+ if ((datadir = getenv("CUPS_DATADIR")) == NULL) 1462+ datadir = CUPS_DATADIR; 1463+ 1464+ snprintf(filename, sizeof(filename), "%s/usb", datadir); 1465+ if ((dir = cupsDirOpen(filename)) == NULL) 1466+ { 1467+ perror(filename); 1468+ return; 1469+ } 1470+ 1471+ fprintf(stderr, "DEBUG: Loading USB quirks from \"%s\".\n", filename); 1472+ 1473+ while ((dent = cupsDirRead(dir)) != NULL) 1474+ { 1475+ if (!S_ISREG(dent->fileinfo.st_mode)) 1476+ continue; 1477+ 1478+ snprintf(filename, sizeof(filename), "%s/usb/%s", datadir, dent->filename); 1479+ if ((fp = cupsFileOpen(filename, "r")) == NULL) 1480+ { 1481+ perror(filename); 1482+ continue; 1483+ } 1484+ 1485+ while (cupsFileGets(fp, line, sizeof(line))) 1486+ { 1487+ /* 1488+ * Skip blank and comment lines... 1489+ */ 1490+ 1491+ if (line[0] == '#' || !line[0]) 1492+ continue; 1493+ 1494+ /* 1495+ * Add a quirk... 1496+ */ 1497+ 1498+ if ((quirk = calloc(1, sizeof(usb_quirk_t))) == NULL) 1499+ { 1500+ perror("DEBUG: Unable to allocate memory for quirk"); 1501+ break; 1502+ } 1503+ 1504+ if (sscanf(line, "%x%x", &quirk->vendor_id, &quirk->product_id) < 1) 1505+ { 1506+ fprintf(stderr, "DEBUG: Bad line: %s\n", line); 1507+ free(quirk); 1508+ continue; 1509+ } 1510+ 1511+ if (strstr(line, " blacklist")) 1512+ quirk->quirks |= USB_QUIRK_BLACKLIST; 1513+ 1514+ if (strstr(line, " delay-close")) 1515+ quirk->quirks |= USB_QUIRK_DELAY_CLOSE; 1516+ 1517+ if (strstr(line, " no-reattach")) 1518+ quirk->quirks |= USB_QUIRK_NO_REATTACH; 1519+ 1520+ if (strstr(line, " soft-reset")) 1521+ quirk->quirks |= USB_QUIRK_SOFT_RESET; 1522+ 1523+ if (strstr(line, " unidir")) 1524+ quirk->quirks |= USB_QUIRK_UNIDIR; 1525+ 1526+ if (strstr(line, " usb-init")) 1527+ quirk->quirks |= USB_QUIRK_USB_INIT; 1528+ 1529+ if (strstr(line, " vendor-class")) 1530+ quirk->quirks |= USB_QUIRK_VENDOR_CLASS; 1531+ 1532+ cupsArrayAdd(all_quirks, quirk); 1533+ } 1534+ 1535+ cupsFileClose(fp); 1536+ } 1537+ 1538+ fprintf(stderr, "DEBUG: Loaded %d quirks.\n", cupsArrayCount(all_quirks)); 1539+ 1540+ cupsDirClose(dir); 1541+} 1542+ 1543+/* 1544+ * 'find_quirks()' - Find the quirks for the given printer, if any. 1545+ * 1546+ * First looks for an exact match, then looks for the vendor ID wildcard match. 1547+ */ 1548+ 1549+static unsigned /* O - Quirks flags */ 1550+find_quirks(int vendor_id, /* I - Vendor ID */ 1551+ int product_id) /* I - Product ID */ 1552+{ 1553+ usb_quirk_t key, /* Search key */ 1554+ *match; /* Matching quirk entry */ 1555+ 1556+ 1557+ key.vendor_id = vendor_id; 1558+ key.product_id = product_id; 1559+ 1560+ if ((match = cupsArrayFind(all_quirks, &key)) != NULL) 1561+ return (match->quirks); 1562+ 1563+ key.product_id = 0; 1564+ 1565+ if ((match = cupsArrayFind(all_quirks, &key)) != NULL) 1566+ return (match->quirks); 1567+ 1568+ return (USB_QUIRK_WHITELIST); 1569+} 1570+ 1571+/* 1572+ * 'compare_quirks()' - Compare two quirks entries. 1573+ */ 1574+ 1575+static int /* O - Result of comparison */ 1576+compare_quirks(usb_quirk_t *a, /* I - First quirk entry */ 1577+ usb_quirk_t *b) /* I - Second quirk entry */ 1578+{ 1579+ int result; /* Result of comparison */ 1580+ 1581+ if ((result = b->vendor_id - a->vendor_id) == 0) 1582+ result = b->product_id - a->product_id; 1583+ 1584+ return (result); 1585+} 1586+ 1587+/* 1588+ * 'print_cb()' - Find a USB printer for printing. 1589+ */ 1590+ 1591+static int /* O - 0 to continue, 1 to stop (found) */ 1592+print_cb(usb_printer_t *printer, /* I - Printer */ 1593+ const char *device_uri, /* I - Device URI */ 1594+ const char *device_id, /* I - IEEE-1284 device ID */ 1595+ const void *data) /* I - User data (make, model, S/N) */ 1596+{ 1597+ char requested_uri[1024], /* Requested URI */ 1598+ *requested_ptr, /* Pointer into requested URI */ 1599+ detected_uri[1024], /* Detected URI */ 1600+ *detected_ptr; /* Pointer into detected URI */ 1601+ 1602+ 1603+ /* 1604+ * If we have an exact match, stop now... 1605+ */ 1606+ 1607+ if (!strcmp((char *)data, device_uri)) 1608+ return (1); 1609+ 1610+ /* 1611+ * Work on copies of the URIs... 1612+ */ 1613+ 1614+ strlcpy(requested_uri, (char *)data, sizeof(requested_uri)); 1615+ strlcpy(detected_uri, device_uri, sizeof(detected_uri)); 1616+ 1617+ /* 1618+ * ohusb-discovered URIs can have an "interface" specification and this 1619+ * never happens for usblp-discovered URIs, so remove the "interface" 1620+ * specification from the URI which we are checking currently. This way a 1621+ * queue for a usblp-discovered printer can now be accessed via ohusb. 1622+ * 1623+ * Similarly, strip "?serial=NNN...NNN" as needed. 1624+ */ 1625+ 1626+ if ((requested_ptr = strstr(requested_uri, "?interface=")) == NULL) 1627+ requested_ptr = strstr(requested_uri, "&interface="); 1628+ if ((detected_ptr = strstr(detected_uri, "?interface=")) == NULL) 1629+ detected_ptr = strstr(detected_uri, "&interface="); 1630+ 1631+ if (!requested_ptr && detected_ptr) 1632+ { 1633+ /* 1634+ * Strip "[?&]interface=nnn" from the detected printer. 1635+ */ 1636+ 1637+ *detected_ptr = '\0'; 1638+ } 1639+ else if (requested_ptr && !detected_ptr) 1640+ { 1641+ /* 1642+ * Strip "[?&]interface=nnn" from the requested printer. 1643+ */ 1644+ 1645+ *requested_ptr = '\0'; 1646+ } 1647+ 1648+ if ((requested_ptr = strstr(requested_uri, "?serial=?")) != NULL) 1649+ { 1650+ /* 1651+ * Strip "?serial=?" from the requested printer. This is a special 1652+ * case, as "?serial=?" means no serial number and not the serial 1653+ * number '?'. This is not covered by the checks below... 1654+ */ 1655+ 1656+ *requested_ptr = '\0'; 1657+ } 1658+ 1659+ if ((requested_ptr = strstr(requested_uri, "?serial=")) == NULL && 1660+ (detected_ptr = strstr(detected_uri, "?serial=")) != NULL) 1661+ { 1662+ /* 1663+ * Strip "?serial=nnn" from the detected printer. 1664+ */ 1665+ 1666+ *detected_ptr = '\0'; 1667+ } 1668+ else if (requested_ptr && !detected_ptr) 1669+ { 1670+ /* 1671+ * Strip "?serial=nnn" from the requested printer. 1672+ */ 1673+ 1674+ *requested_ptr = '\0'; 1675+ } 1676+ 1677+ return (!strcmp(requested_uri, detected_uri)); 1678+} 1679+ 1680+/* 1681+ * 'list_cb()' - List USB printers for discovery. 1682+ */ 1683+ 1684+static int /* O - 0 to continue, 1 to stop */ 1685+list_cb(usb_printer_t *printer, /* I - Printer */ 1686+ const char *device_uri, /* I - Device URI */ 1687+ const char *device_id, /* I - IEEE-1284 device ID */ 1688+ const void *data) /* I - User data (not used) */ 1689+{ 1690+ char make_model[1024]; /* Make and model */ 1691+ 1692+ 1693+ /* 1694+ * Get the device URI and make/model strings... 1695+ */ 1696+ 1697+ if (backendGetMakeModel(device_id, make_model, sizeof(make_model))) 1698+ strlcpy(make_model, "Unknown", sizeof(make_model)); 1699+ 1700+ /* 1701+ * Report the printer... 1702+ */ 1703+ 1704+ cupsBackendReport("direct", device_uri, make_model, make_model, device_id, NULL); 1705+ 1706+ /* 1707+ * Keep going... 1708+ */ 1709+ 1710+ return (0); 1711+} 1712+ 1713+/* 1714+ * 'soft_reset()' - Send a soft reset to the device. 1715+ */ 1716+ 1717+static void 1718+soft_reset(void) 1719+{ 1720+ fd_set input_set; /* Input set for select() */ 1721+ struct timeval tv; /* Time value */ 1722+ char buffer[2048]; /* Buffer */ 1723+ struct timespec cond_timeout; /* pthread condition timeout */ 1724+ 1725+ 1726+ /* 1727+ * Send an abort once a second until the I/O lock is released by the main 1728+ * thread... 1729+ */ 1730+ 1731+ pthread_mutex_lock(&g.readwrite_lock_mutex); 1732+ while (g.readwrite_lock) 1733+ { 1734+ gettimeofday(&tv, NULL); 1735+ cond_timeout.tv_sec = tv.tv_sec + 1; 1736+ cond_timeout.tv_nsec = tv.tv_usec * 1000; 1737+ 1738+ while (g.readwrite_lock) 1739+ { 1740+ if (pthread_cond_timedwait(&g.readwrite_lock_cond, 1741+ &g.readwrite_lock_mutex, 1742+ &cond_timeout) != 0) 1743+ break; 1744+ } 1745+ } 1746+ 1747+ g.readwrite_lock = 1; 1748+ pthread_mutex_unlock(&g.readwrite_lock_mutex); 1749+ 1750+ /* 1751+ * Flush bytes waiting on print_fd... 1752+ */ 1753+ 1754+ g.print_bytes = 0; 1755+ 1756+ FD_ZERO(&input_set); 1757+ FD_SET(g.print_fd, &input_set); 1758+ 1759+ tv.tv_sec = 0; 1760+ tv.tv_usec = 0; 1761+ 1762+ while (select(g.print_fd+1, &input_set, NULL, NULL, &tv) > 0) 1763+ if (read(g.print_fd, buffer, sizeof(buffer)) <= 0) 1764+ break; 1765+ 1766+ /* 1767+ * Send the reset... 1768+ */ 1769+ 1770+ soft_reset_printer(g.printer); 1771+ 1772+ /* 1773+ * Release the I/O lock... 1774+ */ 1775+ 1776+ pthread_mutex_lock(&g.readwrite_lock_mutex); 1777+ g.readwrite_lock = 0; 1778+ pthread_cond_signal(&g.readwrite_lock_cond); 1779+ pthread_mutex_unlock(&g.readwrite_lock_mutex); 1780+} 1781+ 1782+ 1783+/* 1784+ * 'soft_reset_printer()' - Do the soft reset request specific to printers 1785+ * 1786+ * This soft reset is specific to the printer device class and is much less 1787+ * invasive than the general USB reset OH_ResetDevice(). Especially it 1788+ * does never happen that the USB addressing and configuration changes. What 1789+ * is actually done is that all buffers get flushed and the bulk IN and OUT 1790+ * pipes get reset to their default states. This clears all stall conditions. 1791+ * See http://cholla.mmto.org/computers/linux/usb/usbprint11.pdf 1792+ */ 1793+ 1794+static int /* O - 0 on success, < 0 on error */ 1795+soft_reset_printer( 1796+ usb_printer_t *printer) /* I - Printer */ 1797+{ 1798+ ohusb_config_descriptor confptr; /* Pointer to current configuration */ 1799+ int interface, /* Interface to reset */ 1800+ errcode; /* Error code */ 1801+ 1802+ 1803+ if (printer->device == NULL) { 1804+ interface = printer->iface; 1805+ } else { 1806+ confptr = printer->device->config[printer->conf]; 1807+ interface = confptr.interface[printer->iface]. 1808+ altsetting[printer->altset].bInterfaceNumber; 1809+ } 1810+ 1811+ ohusb_control_transfer_parameter ctrlParam = { 1812+ OHUSB_REQUEST_TYPE_CLASS | OHUSB_ENDPOINT_OUT | OHUSB_RECIPIENT_OTHER, 1813+ 2, 0, interface, 5000 1814+ }; 1815+ 1816+ if ((errcode = OH_ControlTransferWrite(printer->pipe, &ctrlParam, NULL, 0)) < 0) 1817+ { 1818+ ctrlParam.requestType = OHUSB_REQUEST_TYPE_CLASS | OHUSB_ENDPOINT_OUT | OHUSB_RECIPIENT_INTERFACE; 1819+ errcode = OH_ControlTransferWrite(printer->pipe, &ctrlParam, NULL, 0); 1820+ } 1821+ 1822+ 1823+ return (errcode); 1824+} 1825\ No newline at end of file 1826diff --git a/backend/usb.c b/backend/usb.c 1827index e1b2c03..50c1bc3 100644 1828--- a/backend/usb.c 1829+++ b/backend/usb.c 1830@@ -42,7 +42,9 @@ int print_device(const char *uri, const char *hostname, 1831 * Include the vendor-specific USB implementation... 1832 */ 1833 1834-#ifdef HAVE_LIBUSB 1835+#ifdef HAVE_OPENHARMONY 1836+# include "usb-oh.c" 1837+#elif defined(HAVE_LIBUSB) 1838 # include "usb-libusb.c" 1839 #elif defined(__APPLE__) 1840 # include "usb-darwin.c" 1841