1diff --git a/backend/usb-oh.c b/backend/usb-oh.c 2new file mode 100644 3index 00000000..d1821dfb 4--- /dev/null 5+++ b/backend/usb-oh.c 6@@ -0,0 +1,1835 @@ 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, int discoveryMode); 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, 0); 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, 0); 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, 0); 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, 0); 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, 0); 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+ int claimedIfId = g.printer->device->config[g.printer->conf].interface[g.printer->iface].altsetting[g.printer->altset].bInterfaceNumber; 463+ 464+ ohusb_transfer_pipe tpipe = { 465+ g.printer->iface, 466+ g.printer->write_endp, 467+ claimedIfId 468+ }; 469+ iostatus = OH_BulkTransferWrite(g.printer->pipe, &tpipe, 470+ print_buffer, g.print_bytes, &bytes, 2000); 471+ /* 472+ * Ignore timeout errors, but retain the number of bytes written to 473+ * avoid sending duplicate data... 474+ */ 475+ 476+ if (iostatus == OHUSB_ERROR_TIMEOUT) 477+ { 478+ fputs("DEBUG: Got USB transaction timeout during write.\n", stderr); 479+ iostatus = 0; 480+ } 481+ 482+ /* 483+ * Retry a write after an aborted write since we probably just got 484+ * SIGTERM... 485+ */ 486+ 487+ else if (iostatus == OHUSB_ERROR_NO_DEVICE) 488+ { 489+ fputs("DEBUG: Got USB return aborted during write.\n", stderr); 490+ 491+ iostatus = OH_BulkTransferWrite(g.printer->pipe, &tpipe, 492+ print_buffer, g.print_bytes, &bytes, 2000); 493+ } 494+ 495+ if (iostatus) 496+ { 497+ /* 498+ * Write error - bail if we don't see an error we can retry... 499+ */ 500+ 501+ _cupsLangPrintFilter(stderr, "ERROR", _("Unable to send data to printer.")); 502+ fprintf(stderr, "DEBUG: ohusb write operation returned %x.\n", iostatus); 503+ 504+ status = CUPS_BACKEND_FAILED; 505+ break; 506+ } 507+ else if (bytes > 0) 508+ { 509+ fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n", (int)bytes); 510+ 511+ g.print_bytes -= bytes; 512+ print_ptr += bytes; 513+ total_bytes += bytes; 514+ } 515+ fprintf(stderr, "DEBUG: %d bytes left to write...\n", (int)g.print_bytes); 516+ } 517+ 518+ if (print_fd != 0 && status == CUPS_BACKEND_OK) 519+ fprintf(stderr, "DEBUG: Sending print file, " CUPS_LLFMT " bytes...\n", 520+ CUPS_LLCAST total_bytes); 521+ } 522+ } 523+ 524+ fprintf(stderr, "DEBUG: Sent " CUPS_LLFMT " bytes...\n", 525+ CUPS_LLCAST total_bytes); 526+ 527+ /* 528+ * Signal the side channel thread to exit... 529+ */ 530+ 531+ if (have_sidechannel) 532+ { 533+ close(CUPS_SC_FD); 534+ pthread_mutex_lock(&g.readwrite_lock_mutex); 535+ g.readwrite_lock = 0; 536+ pthread_cond_signal(&g.readwrite_lock_cond); 537+ pthread_mutex_unlock(&g.readwrite_lock_mutex); 538+ 539+ g.sidechannel_thread_stop = 1; 540+ pthread_mutex_lock(&g.sidechannel_thread_mutex); 541+ 542+ if (!g.sidechannel_thread_done) 543+ { 544+ gettimeofday(&tv, NULL); 545+ cond_timeout.tv_sec = tv.tv_sec + WAIT_SIDE_DELAY; 546+ cond_timeout.tv_nsec = tv.tv_usec * 1000; 547+ 548+ while (!g.sidechannel_thread_done) 549+ { 550+ if (pthread_cond_timedwait(&g.sidechannel_thread_cond, 551+ &g.sidechannel_thread_mutex, 552+ &cond_timeout) != 0) 553+ break; 554+ } 555+ } 556+ 557+ pthread_mutex_unlock(&g.sidechannel_thread_mutex); 558+ } 559+ 560+ /* 561+ * Signal the read thread to exit then wait 7 seconds for it to complete... 562+ */ 563+ 564+ if (have_backchannel) 565+ { 566+ g.read_thread_stop = 1; 567+ 568+ pthread_mutex_lock(&g.read_thread_mutex); 569+ 570+ if (!g.read_thread_done) 571+ { 572+ fputs("DEBUG: Waiting for read thread to exit...\n", stderr); 573+ 574+ gettimeofday(&tv, NULL); 575+ cond_timeout.tv_sec = tv.tv_sec + WAIT_EOF_DELAY; 576+ cond_timeout.tv_nsec = tv.tv_usec * 1000; 577+ 578+ while (!g.read_thread_done) 579+ { 580+ if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex, 581+ &cond_timeout) != 0) 582+ break; 583+ } 584+ 585+ /* 586+ * If it didn't exit abort the pending read and wait an additional 587+ * second... 588+ */ 589+ 590+ if (!g.read_thread_done) 591+ { 592+ fputs("DEBUG: Read thread still active, aborting the pending read...\n", stderr); 593+ 594+ g.wait_eof = 0; 595+ 596+ gettimeofday(&tv, NULL); 597+ cond_timeout.tv_sec = tv.tv_sec + 1; 598+ cond_timeout.tv_nsec = tv.tv_usec * 1000; 599+ 600+ while (!g.read_thread_done) 601+ { 602+ if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex, 603+ &cond_timeout) != 0) 604+ break; 605+ } 606+ } 607+ } 608+ 609+ pthread_mutex_unlock(&g.read_thread_mutex); 610+ } 611+ 612+ /* 613+ * Close the connection and input file and general clean up... 614+ */ 615+ 616+ if (g.printer->quirks & USB_QUIRK_DELAY_CLOSE) 617+ sleep(1); 618+ 619+ close_device(g.printer, 0); 620+ 621+ fputs("DEBUG: print_device out\n", stderr); 622+ return (status); 623+} 624+ 625+/* 626+ * 'find_device()' - Find or enumerate USB printers. 627+ */ 628+ 629+static usb_printer_t * /* O - Found printer */ 630+find_device(usb_cb_t cb, /* I - Callback function */ 631+ const void *data) /* I - User data for callback */ 632+{ 633+ ohusb_device_descriptor *list = NULL; /* List of connected USB devices */ 634+ ohusb_device_descriptor *device = NULL; /* Current device */ 635+ ohusb_config_descriptor *confptr = NULL; /* Pointer to current configuration */ 636+ const ohusb_interface *ifaceptr = NULL; /* Pointer to current interface */ 637+ const ohusb_interface_descriptor *altptr = NULL; /* Pointer to current alternate setting */ 638+ const ohusb_endpoint_descriptor *endpptr = NULL; /* Pointer to current endpoint */ 639+ ssize_t numdevs, /* number of connected devices */ 640+ i = 0; 641+ uint8_t conf, /* Current configuration */ 642+ iface, /* Current interface */ 643+ altset, /* Current alternate setting */ 644+ protocol, /* Current protocol */ 645+ endp, /* Current endpoint */ 646+ read_endp, /* Current read endpoint */ 647+ write_endp; /* Current write endpoint */ 648+ char device_id[1024], /* IEEE-1284 device ID */ 649+ device_uri[1024]; /* Device URI */ 650+ static usb_printer_t printer; /* Current printer */ 651+ int32_t ret; 652+ 653+ /* 654+ * get ohusb devices... 655+ */ 656+ 657+ fputs("DEBUG: find_device\n", stderr); 658+ ret = OH_GetDevices(&list, &numdevs); 659+ if (ret != OHUSB_SUCCESS) { 660+ fprintf(stderr, "DEBUG: find_device OH_GetDevices fail\n"); 661+ return (NULL); 662+ } 663+ fprintf(stderr, "DEBUG: find_device OH_GetDevices numdevs=%d\n", (int)numdevs); 664+ 665+ /* 666+ * Then loop through the devices it found... 667+ */ 668+ 669+ if (numdevs > 0) 670+ for (i = 0; i < numdevs; i++) 671+ { 672+ device = list + i; 673+ 674+ /* 675+ * Ignore devices with no configuration data and anything that is not 676+ * a printer... 677+ */ 678+ 679+ if (device == NULL) 680+ continue; 681+ 682+ fprintf(stderr, "DEBUG: OH_GetDevices index=%zd, busNum=%d, devAddr=%d, idVendor=%d, idProduct=%d\n", 683+ i, device->busNum, device->devAddr, device->idVendor, device->idProduct); 684+ 685+ if (!device->bNumConfigurations || !device->idVendor || !device->idProduct) 686+ continue; 687+ 688+ printer.quirks = find_quirks(device->idVendor, device->idProduct); 689+ fprintf(stderr, "DEBUG: find_device quirks=%d\n", printer.quirks); 690+ 691+ /* 692+ * Ignore blacklisted printers... 693+ */ 694+ 695+ if (printer.quirks & USB_QUIRK_BLACKLIST) 696+ continue; 697+ 698+ for (conf = 0, confptr = device->config; conf < device->bNumConfigurations; conf ++, confptr ++) 699+ { 700+ if (confptr == NULL) 701+ continue; 702+ for (iface = 0, ifaceptr = confptr->interface; 703+ iface < confptr->bNumInterfaces; 704+ iface ++, ifaceptr ++) 705+ { 706+ /* 707+ * Some printers offer multiple interfaces... 708+ */ 709+ 710+ protocol = 0; 711+ if (ifaceptr == NULL) 712+ continue; 713+ 714+ for (altset = 0, altptr = ifaceptr->altsetting; 715+ altset < ifaceptr->num_altsetting; 716+ altset ++, altptr ++) 717+ { 718+ if (altptr == NULL) 719+ continue; 720+ /* 721+ * Currently we only support unidirectional and bidirectional 722+ * printers. Future versions of this code will support the 723+ * 1284.4 (packet mode) protocol as well. 724+ */ 725+ fprintf(stderr, "DEBUG: find_device class=%x, subclass=%x, protocol=%x\n", 726+ altptr->bInterfaceClass, altptr->bInterfaceSubClass, altptr->bInterfaceProtocol); 727+ if (((altptr->bInterfaceClass != OHUSB_CLASS_PRINTER || altptr->bInterfaceSubClass != 1) && 728+ ((printer.quirks & USB_QUIRK_VENDOR_CLASS) == 0)) || 729+ (altptr->bInterfaceProtocol != 1 && /* Unidirectional */ 730+ altptr->bInterfaceProtocol != 2) || /* Bidirectional */ 731+ altptr->bInterfaceProtocol < protocol) 732+ { 733+ fprintf(stderr, "DEBUG: Not a usb printer.\n"); 734+ continue; 735+ } 736+ 737+ if (printer.quirks & USB_QUIRK_VENDOR_CLASS) 738+ fprintf(stderr, "DEBUG: Printer does not report class 7 and/or " 739+ "subclass 1 but works as a printer anyway\n"); 740+ 741+ read_endp = 0xff; 742+ write_endp = 0xff; 743+ 744+ for (endp = 0, endpptr = altptr->endpoint; 745+ endp < altptr->bNumEndpoints; 746+ endp ++, endpptr ++) 747+ { 748+ if ((endpptr->bmAttributes & OHUSB_TRANSFER_TYPE_MASK) == OHUSB_TRANSFER_TYPE_BULK) 749+ { 750+ if (endpptr->bEndpointAddress & OHUSB_ENDPOINT_DIR_MASK) 751+ read_endp = endp; 752+ else 753+ write_endp = endp; 754+ } 755+ } 756+ 757+ if (write_endp != 0xff) 758+ { 759+ /* 760+ * Save the best match so far... 761+ */ 762+ 763+ protocol = altptr->bInterfaceProtocol; 764+ printer.altset = altset; 765+ printer.write_endp = write_endp; 766+ if (protocol > 1) 767+ printer.read_endp = read_endp; 768+ else 769+ printer.read_endp = -1; 770+ } 771+ } 772+ 773+ if (protocol > 0) 774+ { 775+ printer.device = device; 776+ printer.conf = conf; 777+ printer.iface = iface; 778+ printer.protocol = protocol; 779+ printer.pipe = NULL; 780+ 781+ if (!open_device(&printer, data != NULL)) 782+ { 783+ get_device_id(&printer, device_id, sizeof(device_id)); 784+ make_device_uri(&printer, device_id, device_uri, sizeof(device_uri)); 785+ 786+ fprintf(stderr, "DEBUG2: Printer found with device ID: %s " 787+ "Device URI: %s\n", 788+ device_id, device_uri); 789+ 790+ if ((*cb)(&printer, device_uri, device_id, data)) 791+ { 792+ fprintf(stderr, "DEBUG: Device protocol: %d\n", printer.protocol); 793+ if (printer.quirks & USB_QUIRK_UNIDIR) 794+ { 795+ printer.read_endp = -1; 796+ fprintf(stderr, "DEBUG: Printer reports bi-di support " 797+ "but in reality works only uni-directionally\n"); 798+ } 799+ if (printer.read_endp != -1) 800+ { 801+ printer.read_endp = confptr->interface[printer.iface]. 802+ altsetting[printer.altset]. 803+ endpoint[printer.read_endp]. 804+ bEndpointAddress; 805+ } 806+ else 807+ fprintf(stderr, "DEBUG: Uni-directional USB communication " 808+ "only!\n"); 809+ printer.write_endp = confptr->interface[printer.iface]. 810+ altsetting[printer.altset]. 811+ endpoint[printer.write_endp]. 812+ bEndpointAddress; 813+ if (printer.quirks & USB_QUIRK_NO_REATTACH) 814+ { 815+ printer.usblp_attached = 0; 816+ fprintf(stderr, "DEBUG: Printer does not like usblp " 817+ "kernel module to be re-attached after job\n"); 818+ } 819+ return (&printer); 820+ } 821+ 822+ close_device(&printer, data == NULL); 823+ } 824+ } 825+ } 826+ } 827+ } 828+ 829+ fputs("DEBUG: find_device out\n", stderr); 830+ return (NULL); 831+} 832+ 833+/* 834+ * 'open_device()' - Open a connection to the USB printer. 835+ */ 836+ 837+static int /* O - 0 on success, -1 on error */ 838+open_device(usb_printer_t *printer, /* I - Printer */ 839+ int verbose) /* I - Update connecting-to-device state? */ 840+{ 841+ ohusb_config_descriptor confptr; 842+ /* Pointer to current configuration */ 843+ int number1 = -1, /* Configuration/interface/altset */ 844+ number2 = -1, /* numbers */ 845+ errcode = 0; 846+ char current; /* Current configuration */ 847+ 848+ fprintf(stderr, "DEBUG: open_device\n"); 849+ 850+ /* 851+ * Return immediately if we are already connected... 852+ */ 853+ 854+ if (printer->pipe) 855+ return (0); 856+ 857+ /* 858+ * Try opening the printer... 859+ */ 860+ 861+ if ((errcode = OH_OpenDevice(printer->device, &(printer->pipe))) < 0) 862+ { 863+ fprintf(stderr, "DEBUG: Failed to open device, code: %d\n", errcode); 864+ return (-1); 865+ } 866+ fprintf(stderr, "DEBUG: OH_OpenDevice success busNum=%d, devAddr=%d\n", 867+ printer->pipe->busNum, printer->pipe->devAddr); 868+ 869+ printer->usblp_attached = 0; 870+ printer->reset_after_job = 0; 871+ 872+ if (verbose) 873+ fputs("STATE: +connecting-to-device\n", stderr); 874+ if (printer->device == NULL) 875+ { 876+ fprintf(stderr, "DEBUG: Failed to get device descriptor, code: %d\n", errcode); 877+ goto error; 878+ } 879+ 880+ /* 881+ * Set the desired configuration, but only if it needs changing. Some 882+ * printers (e.g., Samsung) don't like OH_SetConfiguration. It will 883+ * succeed, but the following print job is sometimes silently lost by the 884+ * printer. 885+ */ 886+ 887+ ohusb_control_transfer_parameter ctrlParam = { 888+ OHUSB_REQUEST_TYPE_STANDARD | OHUSB_ENDPOINT_IN | OHUSB_RECIPIENT_DEVICE, 889+ 8, 0, 0, 5000 890+ }; 891+ 892+ if (OH_ControlTransferRead(printer->pipe, &ctrlParam, (unsigned char *)¤t, 1) <= 0) 893+ { 894+ current = 0; /* Assume not configured */ 895+ } 896+ 897+ printer->origconf = current; 898+ fprintf(stderr, "DEBUG: open_device OH_ControlTransferRead current = %02x\n", current); 899+ 900+ confptr = printer->device->config[printer->conf]; 901+ number1 = confptr.iConfiguration; 902+ 903+ if (number1 != current) 904+ { 905+ fprintf(stderr, "DEBUG: Switching USB device configuration: %d -> %d\n", 906+ current, number1); 907+ if ((errcode = OH_SetConfiguration(printer->pipe, number1)) < 0) 908+ { 909+ /* 910+ * If the set fails, chances are that the printer only supports a 911+ * single configuration. Technically these printers don't conform to 912+ * the USB printer specification, but otherwise they'll work... 913+ */ 914+ 915+ if (errcode != OHUSB_ERROR_BUSY) 916+ fprintf(stderr, "DEBUG: Failed to set configuration %d for %04x:%04x\n", 917+ number1, printer->device->idVendor, printer->device->idProduct); 918+ } 919+ } 920+ 921+ /* 922+ * Claim interfaces when printing... 923+ */ 924+ 925+ if (verbose) 926+ { 927+ /* 928+ * Claim interfaces as needed... 929+ */ 930+ 931+ number1 = confptr.interface[printer->iface].altsetting[printer->altset].bInterfaceNumber; 932+ 933+ if ((errcode = OH_ClaimInterface(printer->pipe, number1, true)) < 0) 934+ { 935+ fprintf(stderr, 936+ "DEBUG: Failed to claim interface %d for %04x:%04x: %s\n", 937+ number1, printer->device->idVendor, printer->device->idProduct, strerror(errno)); 938+ 939+ goto error; 940+ } 941+ 942+ /* 943+ * Set alternate setting, but only if there is more than one option. Some 944+ * printers (e.g., Samsung) don't like usb_set_altinterface. 945+ */ 946+ 947+ number2 = confptr.interface[printer->iface]. 948+ altsetting[printer->altset].bAlternateSetting; 949+ if (confptr.interface[printer->iface].num_altsetting > 1 && number2 > 0) 950+ { 951+ number1 = confptr.interface[printer->iface]. 952+ altsetting[printer->altset].bInterfaceNumber; 953+ while ((errcode = OH_SetInterface(printer->pipe, number1, number2)) < 0) 954+ { 955+ if (errcode != OHUSB_ERROR_BUSY) 956+ { 957+ fprintf(stderr, 958+ "DEBUG: Failed to set alternate interface %d for %04x:%04x: " 959+ "%s\n", 960+ number2, printer->device->idVendor, printer->device->idProduct, strerror(errno)); 961+ 962+ goto error; 963+ } 964+ } 965+ } 966+ } 967+ 968+ if (verbose) 969+ fputs("STATE: -connecting-to-device\n", stderr); 970+ 971+ return (0); 972+ 973+ /* 974+ * If we get here, there was a hard error... 975+ */ 976+ 977+ error: 978+ 979+ if (verbose) 980+ fputs("STATE: -connecting-to-device\n", stderr); 981+ 982+ OH_CloseDevice(printer->pipe); 983+ printer->pipe = NULL; 984+ 985+ return (-1); 986+} 987+ 988+/* 989+ * 'get_device_id()' - Get the IEEE-1284 device ID for the printer. 990+ */ 991+ 992+static int /* O - 0 on success, -1 on error */ 993+get_device_id(usb_printer_t *printer, /* I - Printer */ 994+ char *buffer, /* I - String buffer */ 995+ size_t bufsize) /* I - Number of bytes in buffer */ 996+{ 997+ fprintf(stderr, "DEBUG: get_device_id\n"); 998+ 999+ int length; /* Length of device ID */ 1000+ 1001+ ohusb_control_transfer_parameter ctrlParam = { 1002+ OHUSB_REQUEST_TYPE_CLASS | OHUSB_ENDPOINT_IN | OHUSB_RECIPIENT_INTERFACE, 1003+ 0, printer->conf, (printer->iface << 8) | printer->altset, 5000 1004+ }; 1005+ 1006+ if (OH_ControlTransferRead(printer->pipe, &ctrlParam, (unsigned char *)buffer, bufsize) <= 0) 1007+ { 1008+ *buffer = '\0'; 1009+ return (-1); 1010+ } 1011+ 1012+ /* 1013+ * Extract the length of the device ID string from the first two 1014+ * bytes. The 1284 spec says the length is stored MSB first... 1015+ */ 1016+ 1017+ length = (int)((((unsigned)buffer[0] & 255) << 8) | ((unsigned)buffer[1] & 255)); 1018+ 1019+ /* 1020+ * Check to see if the length is larger than our buffer or less than 14 bytes 1021+ * (the minimum valid device ID is "MFG:x;MDL:y;" with 2 bytes for the length). 1022+ * 1023+ * If the length is out-of-range, assume that the vendor incorrectly 1024+ * implemented the 1284 spec and re-read the length as LSB first,.. 1025+ */ 1026+ 1027+ if (length > bufsize || length < 14) 1028+ length = (int)((((unsigned)buffer[1] & 255) << 8) | ((unsigned)buffer[0] & 255)); 1029+ 1030+ if (length > bufsize) 1031+ length = bufsize; 1032+ 1033+ if (length < 14) 1034+ { 1035+ /* 1036+ * Invalid device ID, clear it! 1037+ */ 1038+ 1039+ *buffer = '\0'; 1040+ fprintf(stderr, "DEBUG: get_device_id Invalid device ID\n"); 1041+ return (-1); 1042+ } 1043+ 1044+ length -= 2; 1045+ fprintf(stderr, "DEBUG: get_device_id length = %d\n", length); 1046+ 1047+ /* 1048+ * Copy the device ID text to the beginning of the buffer and 1049+ * nul-terminate. 1050+ */ 1051+ 1052+ memmove(buffer, buffer + 2, (size_t)length); 1053+ buffer[length] = '\0'; 1054+ 1055+ return (0); 1056+} 1057+ 1058+/* 1059+ * 'make_device_uri()' - Create a device URI for a USB printer. 1060+ */ 1061+ 1062+static char * /* O - Device URI */ 1063+make_device_uri( 1064+ usb_printer_t *printer, /* I - Printer */ 1065+ const char *device_id, /* I - IEEE-1284 device ID */ 1066+ char *uri, /* I - Device URI buffer */ 1067+ size_t uri_size) /* I - Size of device URI buffer */ 1068+{ 1069+ char options[1024]; /* Device URI options */ 1070+ int num_values; /* Number of 1284 parameters */ 1071+ cups_option_t *values; /* 1284 parameters */ 1072+ const char *mfg, /* Manufacturer */ 1073+ *mdl, /* Model */ 1074+ *des = NULL, /* Description */ 1075+ *sern = NULL; /* Serial number */ 1076+ size_t mfglen; /* Length of manufacturer string */ 1077+ char tempmdl[256], /* Temporary model string */ 1078+ tempmfg[256], /* Temporary manufacturer string */ 1079+ tempsern[256], /* Temporary serial number string */ 1080+ *tempptr; /* Pointer into temp string */ 1081+ 1082+ fprintf(stderr, "DEBUG: make_device_uri\n"); 1083+ 1084+ /* 1085+ * Get the make, model, and serial numbers... 1086+ */ 1087+ 1088+ num_values = _cupsGet1284Values(device_id, &values); 1089+ 1090+ if (printer->device != NULL && printer->device->iSerialNumber) 1091+ { 1092+ // Try getting the serial number from the device itself... 1093+ int length = OH_GetStringDescriptor(printer->pipe, printer->device->iSerialNumber, (unsigned char *)tempsern, sizeof(tempsern) - 1); 1094+ if (length > 0) 1095+ { 1096+ tempsern[length] = '\0'; 1097+ sern = tempsern; 1098+ } 1099+ else 1100+ fputs("DEBUG2: iSerialNumber could not be read.\n", stderr); 1101+ } 1102+ else 1103+ fputs("DEBUG2: iSerialNumber is not present.\n", stderr); 1104+ 1105+ if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL) 1106+ { 1107+ if ((mfg = cupsGetOption("MFG", num_values, values)) == NULL && printer->device->iManufacturer) 1108+ { 1109+ int length = OH_GetStringDescriptor(printer->pipe, printer->device->iManufacturer, (unsigned char *)tempmfg, sizeof(tempmfg) - 1); 1110+ if (length > 0) 1111+ { 1112+ tempmfg[length] = '\0'; 1113+ mfg = tempmfg; 1114+ } 1115+ } 1116+ } 1117+ 1118+ if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL) 1119+ { 1120+ if ((mdl = cupsGetOption("MDL", num_values, values)) == NULL && printer->device->iProduct) 1121+ { 1122+ int length = OH_GetStringDescriptor(printer->pipe, printer->device->iProduct, (unsigned char *)tempmdl, sizeof(tempmdl) - 1); 1123+ if (length > 0) 1124+ { 1125+ tempmdl[length] = '\0'; 1126+ mdl = tempmdl; 1127+ } 1128+ } 1129+ } 1130+ 1131+ /* 1132+ * To maintain compatibility with the original character device backend on 1133+ * Linux and *BSD, map manufacturer names... 1134+ */ 1135+ 1136+ if (mfg) 1137+ { 1138+ if (!_cups_strcasecmp(mfg, "Hewlett-Packard")) 1139+ mfg = "HP"; 1140+ else if (!_cups_strcasecmp(mfg, "Lexmark International")) 1141+ mfg = "Lexmark"; 1142+ } 1143+ else 1144+ { 1145+ /* 1146+ * No manufacturer? Use the model string or description... 1147+ */ 1148+ 1149+ if (mdl) 1150+ _ppdNormalizeMakeAndModel(mdl, tempmfg, sizeof(tempmfg)); 1151+ else if ((des = cupsGetOption("DESCRIPTION", num_values, values)) != NULL || 1152+ (des = cupsGetOption("DES", num_values, values)) != NULL) 1153+ _ppdNormalizeMakeAndModel(des, tempmfg, sizeof(tempmfg)); 1154+ else 1155+ strlcpy(tempmfg, "Unknown", sizeof(tempmfg)); 1156+ 1157+ if ((tempptr = strchr(tempmfg, ' ')) != NULL) 1158+ *tempptr = '\0'; 1159+ 1160+ mfg = tempmfg; 1161+ } 1162+ 1163+ if (!mdl) 1164+ { 1165+ /* 1166+ * No model? Use description... 1167+ */ 1168+ if (des) 1169+ mdl = des; /* We remove the manufacturer name below */ 1170+ else if (!strncasecmp(mfg, "Unknown", 7)) 1171+ mdl = "Printer"; 1172+ else 1173+ mdl = "Unknown Model"; 1174+ } 1175+ 1176+ mfglen = strlen(mfg); 1177+ 1178+ if (!strncasecmp(mdl, mfg, mfglen) && _cups_isspace(mdl[mfglen])) 1179+ { 1180+ mdl += mfglen + 1; 1181+ 1182+ while (_cups_isspace(*mdl)) 1183+ mdl ++; 1184+ } 1185+ 1186+ /* 1187+ * Generate the device URI from the manufacturer, model, serial number, 1188+ * and interface number... 1189+ */ 1190+ 1191+ if (sern) 1192+ { 1193+ if (printer->iface > 0) 1194+ snprintf(options, sizeof(options), "?serial=%s&interface=%d", sern, printer->iface); 1195+ else 1196+ snprintf(options, sizeof(options), "?serial=%s", sern); 1197+ } 1198+ else if (printer->iface > 0) 1199+ snprintf(options, sizeof(options), "?interface=%d", printer->iface); 1200+ else 1201+ options[0] = '\0'; 1202+ 1203+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, uri_size, "usb", NULL, mfg, 0, "/%s%s", mdl, options); 1204+ 1205+ fprintf(stderr, "DEBUG2: make_device_uri sern=\"%s\", mfg=\"%s\", mdl=\"%s\"\n", sern, mfg, mdl); 1206+ 1207+ cupsFreeOptions(num_values, values); 1208+ 1209+ return (uri); 1210+} 1211+ 1212+/* 1213+ * 'close_device()' - Close the connection to the USB printer. 1214+ */ 1215+ 1216+static int /* I - 0 on success, -1 on failure */ 1217+close_device(usb_printer_t *printer, /* I - Printer */ 1218+ int discoveryMode) /* I - Discovery mode */ 1219+{ 1220+ ohusb_config_descriptor confptr; /* Pointer to current configuration */ 1221+ 1222+ if (printer->pipe) 1223+ { 1224+ /* 1225+ * Release interfaces before closing so that we know all data is written 1226+ * to the device... 1227+ */ 1228+ 1229+ int errcode; /* Return value of ohusb function */ 1230+ int number1, /* Interface number */ 1231+ number2; /* Configuration number */ 1232+ 1233+ if (printer->device != NULL && printer->device->config != NULL) 1234+ { 1235+ confptr = printer->device->config[printer->conf]; 1236+ number1 = confptr.interface[printer->iface]. 1237+ altsetting[printer->altset].bInterfaceNumber; 1238+ if (!discoveryMode) 1239+ { 1240+ OH_ReleaseInterface(printer->pipe, number1); 1241+ } 1242+ 1243+ number2 = confptr.iConfiguration; 1244+ 1245+ /* 1246+ * If we have changed the configuration from one valid configuration 1247+ * to another, restore the old one 1248+ */ 1249+ if (printer->origconf > 0 && printer->origconf != number2) 1250+ { 1251+ fprintf(stderr, "DEBUG: Restoring USB device configuration: %d -> %d\n", 1252+ number2, printer->origconf); 1253+ if ((errcode = OH_SetConfiguration(printer->pipe, printer->origconf)) < 0) 1254+ { 1255+ fprintf(stderr, 1256+ "DEBUG: Failed to set configuration %d for %04x:%04x\n", 1257+ printer->origconf, printer->device->idVendor, printer->device->idProduct); 1258+ } 1259+ } 1260+ } 1261+ else 1262+ fprintf(stderr, 1263+ "DEBUG: Failed to get configuration descriptor %d\n", 1264+ printer->conf); 1265+ 1266+ /* 1267+ * Close the interface and return... 1268+ */ 1269+ 1270+ if (OH_CloseDevice(printer->pipe) == OHUSB_SUCCESS) 1271+ printer->pipe = NULL; 1272+ } 1273+ 1274+ return (0); 1275+} 1276+ 1277+/* 1278+ * 'read_thread()' - Thread to read the backchannel data on. 1279+ */ 1280+ 1281+static void *read_thread(void *reference) 1282+{ 1283+ unsigned char readbuffer[512]; 1284+ int rbytes; 1285+ int readstatus; 1286+ ohusb_transfer_pipe tpipe = { 1287+ g.printer->iface, 1288+ g.printer->read_endp 1289+ }; 1290+ 1291+ 1292+ (void)reference; 1293+ 1294+ do 1295+ { 1296+ /* 1297+ * Try reading from the OUT (to host) endpoint... 1298+ */ 1299+ 1300+ rbytes = sizeof(readbuffer); 1301+ readstatus = OH_BulkTransferRead(g.printer->pipe, 1302+ &tpipe, readbuffer, rbytes, &rbytes); 1303+ if (readstatus == OHUSB_SUCCESS && rbytes > 0) 1304+ { 1305+ fprintf(stderr, "DEBUG: Read %d bytes of back-channel data...\n", (int)rbytes); 1306+ cupsBackChannelWrite((const char *)readbuffer, (size_t)rbytes, 1.0); 1307+ } 1308+ else 1309+ fprintf(stderr, "DEBUG: Got USB transaction error during read, errorcode=%d\n", readstatus); 1310+ 1311+ /* 1312+ * Make sure this loop executes no more than once every 250 miliseconds... 1313+ */ 1314+ 1315+ if ((readstatus != OHUSB_SUCCESS || rbytes == 0) && (g.wait_eof || !g.read_thread_stop)) 1316+ usleep(250000); 1317+ } 1318+ while (g.wait_eof || !g.read_thread_stop); 1319+ 1320+ /* 1321+ * Let the main thread know that we have completed the read thread... 1322+ */ 1323+ 1324+ pthread_mutex_lock(&g.read_thread_mutex); 1325+ g.read_thread_done = 1; 1326+ pthread_cond_signal(&g.read_thread_cond); 1327+ pthread_mutex_unlock(&g.read_thread_mutex); 1328+ 1329+ return (NULL); 1330+} 1331+ 1332+/* 1333+ * 'sidechannel_thread()' - Handle side-channel requests. 1334+ */ 1335+ 1336+static void* 1337+sidechannel_thread(void *reference) 1338+{ 1339+ cups_sc_command_t command; /* Request command */ 1340+ cups_sc_status_t status; /* Request/response status */ 1341+ char data[2048]; /* Request/response data */ 1342+ int datalen; /* Request/response data size */ 1343+ 1344+ 1345+ (void)reference; 1346+ 1347+ do 1348+ { 1349+ datalen = sizeof(data); 1350+ 1351+ if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0)) 1352+ { 1353+ if (status == CUPS_SC_STATUS_TIMEOUT) 1354+ continue; 1355+ else 1356+ break; 1357+ } 1358+ 1359+ switch (command) 1360+ { 1361+ case CUPS_SC_CMD_SOFT_RESET: /* Do a soft reset */ 1362+ fputs("DEBUG: CUPS_SC_CMD_SOFT_RESET received from driver...\n", stderr); 1363+ 1364+ soft_reset(); 1365+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, NULL, 0, 1.0); 1366+ fputs("DEBUG: Returning status CUPS_STATUS_OK with no bytes...\n", 1367+ stderr); 1368+ break; 1369+ 1370+ case CUPS_SC_CMD_DRAIN_OUTPUT: /* Drain all pending output */ 1371+ fputs("DEBUG: CUPS_SC_CMD_DRAIN_OUTPUT received from driver...\n", stderr); 1372+ 1373+ g.drain_output = 1; 1374+ break; 1375+ 1376+ case CUPS_SC_CMD_GET_BIDI: /* Is the connection bidirectional? */ 1377+ fputs("DEBUG: CUPS_SC_CMD_GET_BIDI received from driver...\n", stderr); 1378+ 1379+ data[0] = (g.printer->protocol >= 2 ? 1 : 0); 1380+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0); 1381+ 1382+ fprintf(stderr, 1383+ "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n", 1384+ data[0]); 1385+ break; 1386+ 1387+ case CUPS_SC_CMD_GET_DEVICE_ID: /* Return IEEE-1284 device ID */ 1388+ fputs("DEBUG: CUPS_SC_CMD_GET_DEVICE_ID received from driver...\n", stderr); 1389+ 1390+ datalen = sizeof(data); 1391+ if (get_device_id(g.printer, data, sizeof(data))) 1392+ { 1393+ status = CUPS_SC_STATUS_IO_ERROR; 1394+ datalen = 0; 1395+ } 1396+ else 1397+ { 1398+ status = CUPS_SC_STATUS_OK; 1399+ datalen = strlen(data); 1400+ } 1401+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, datalen, 1.0); 1402+ 1403+ if (datalen < sizeof(data)) 1404+ data[datalen] = '\0'; 1405+ else 1406+ data[sizeof(data) - 1] = '\0'; 1407+ 1408+ fprintf(stderr, 1409+ "DEBUG: Returning CUPS_SC_STATUS_OK with %d bytes (%s)...\n", 1410+ datalen, data); 1411+ break; 1412+ 1413+ case CUPS_SC_CMD_GET_STATE: /* Return device state */ 1414+ fputs("DEBUG: CUPS_SC_CMD_GET_STATE received from driver...\n", stderr); 1415+ 1416+ data[0] = CUPS_SC_STATE_ONLINE; 1417+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0); 1418+ 1419+ fprintf(stderr, 1420+ "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n", 1421+ data[0]); 1422+ break; 1423+ 1424+ case CUPS_SC_CMD_GET_CONNECTED: /* Return whether device is 1425+ connected */ 1426+ fputs("DEBUG: CUPS_SC_CMD_GET_CONNECTED received from driver...\n", stderr); 1427+ 1428+ data[0] = (g.printer->device ? 1 : 0); 1429+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0); 1430+ 1431+ fprintf(stderr, 1432+ "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n", 1433+ data[0]); 1434+ break; 1435+ 1436+ default: 1437+ fprintf(stderr, "DEBUG: Unknown side-channel command (%d) received " 1438+ "from driver...\n", command); 1439+ 1440+ cupsSideChannelWrite(command, CUPS_SC_STATUS_NOT_IMPLEMENTED, NULL, 0, 1.0); 1441+ 1442+ fputs("DEBUG: Returned CUPS_SC_STATUS_NOT_IMPLEMENTED with no bytes...\n", stderr); 1443+ break; 1444+ } 1445+ } 1446+ while (!g.sidechannel_thread_stop); 1447+ 1448+ pthread_mutex_lock(&g.sidechannel_thread_mutex); 1449+ g.sidechannel_thread_done = 1; 1450+ pthread_cond_signal(&g.sidechannel_thread_cond); 1451+ pthread_mutex_unlock(&g.sidechannel_thread_mutex); 1452+ 1453+ return (NULL); 1454+} 1455+ 1456+/* 1457+ * 'load_quirks()' - Load all quirks files in the /usr/share/cups/usb directory. 1458+ */ 1459+ 1460+static void 1461+load_quirks(void) 1462+{ 1463+ const char *datadir; /* CUPS_DATADIR environment variable */ 1464+ char filename[1024], /* Filename */ 1465+ line[1024]; /* Line from file */ 1466+ cups_dir_t *dir; /* Directory */ 1467+ cups_dentry_t *dent; /* Directory entry */ 1468+ cups_file_t *fp; /* Quirks file */ 1469+ usb_quirk_t *quirk; /* New quirk */ 1470+ 1471+ 1472+ all_quirks = cupsArrayNew((cups_array_func_t)compare_quirks, NULL); 1473+ 1474+ if ((datadir = getenv("CUPS_DATADIR")) == NULL) 1475+ datadir = CUPS_DATADIR; 1476+ 1477+ snprintf(filename, sizeof(filename), "%s/usb", datadir); 1478+ if ((dir = cupsDirOpen(filename)) == NULL) 1479+ { 1480+ perror(filename); 1481+ return; 1482+ } 1483+ 1484+ fprintf(stderr, "DEBUG: Loading USB quirks from \"%s\".\n", filename); 1485+ 1486+ while ((dent = cupsDirRead(dir)) != NULL) 1487+ { 1488+ if (!S_ISREG(dent->fileinfo.st_mode)) 1489+ continue; 1490+ 1491+ snprintf(filename, sizeof(filename), "%s/usb/%s", datadir, dent->filename); 1492+ if ((fp = cupsFileOpen(filename, "r")) == NULL) 1493+ { 1494+ perror(filename); 1495+ continue; 1496+ } 1497+ 1498+ while (cupsFileGets(fp, line, sizeof(line))) 1499+ { 1500+ /* 1501+ * Skip blank and comment lines... 1502+ */ 1503+ 1504+ if (line[0] == '#' || !line[0]) 1505+ continue; 1506+ 1507+ /* 1508+ * Add a quirk... 1509+ */ 1510+ 1511+ if ((quirk = calloc(1, sizeof(usb_quirk_t))) == NULL) 1512+ { 1513+ perror("DEBUG: Unable to allocate memory for quirk"); 1514+ break; 1515+ } 1516+ 1517+ if (sscanf(line, "%x%x", &quirk->vendor_id, &quirk->product_id) < 1) 1518+ { 1519+ fprintf(stderr, "DEBUG: Bad line: %s\n", line); 1520+ free(quirk); 1521+ continue; 1522+ } 1523+ 1524+ if (strstr(line, " blacklist")) 1525+ quirk->quirks |= USB_QUIRK_BLACKLIST; 1526+ 1527+ if (strstr(line, " delay-close")) 1528+ quirk->quirks |= USB_QUIRK_DELAY_CLOSE; 1529+ 1530+ if (strstr(line, " no-reattach")) 1531+ quirk->quirks |= USB_QUIRK_NO_REATTACH; 1532+ 1533+ if (strstr(line, " soft-reset")) 1534+ quirk->quirks |= USB_QUIRK_SOFT_RESET; 1535+ 1536+ if (strstr(line, " unidir")) 1537+ quirk->quirks |= USB_QUIRK_UNIDIR; 1538+ 1539+ if (strstr(line, " usb-init")) 1540+ quirk->quirks |= USB_QUIRK_USB_INIT; 1541+ 1542+ if (strstr(line, " vendor-class")) 1543+ quirk->quirks |= USB_QUIRK_VENDOR_CLASS; 1544+ 1545+ cupsArrayAdd(all_quirks, quirk); 1546+ } 1547+ 1548+ cupsFileClose(fp); 1549+ } 1550+ 1551+ fprintf(stderr, "DEBUG: Loaded %d quirks.\n", cupsArrayCount(all_quirks)); 1552+ 1553+ cupsDirClose(dir); 1554+} 1555+ 1556+/* 1557+ * 'find_quirks()' - Find the quirks for the given printer, if any. 1558+ * 1559+ * First looks for an exact match, then looks for the vendor ID wildcard match. 1560+ */ 1561+ 1562+static unsigned /* O - Quirks flags */ 1563+find_quirks(int vendor_id, /* I - Vendor ID */ 1564+ int product_id) /* I - Product ID */ 1565+{ 1566+ usb_quirk_t key, /* Search key */ 1567+ *match; /* Matching quirk entry */ 1568+ 1569+ 1570+ key.vendor_id = vendor_id; 1571+ key.product_id = product_id; 1572+ 1573+ if ((match = cupsArrayFind(all_quirks, &key)) != NULL) 1574+ return (match->quirks); 1575+ 1576+ key.product_id = 0; 1577+ 1578+ if ((match = cupsArrayFind(all_quirks, &key)) != NULL) 1579+ return (match->quirks); 1580+ 1581+ return (USB_QUIRK_WHITELIST); 1582+} 1583+ 1584+/* 1585+ * 'compare_quirks()' - Compare two quirks entries. 1586+ */ 1587+ 1588+static int /* O - Result of comparison */ 1589+compare_quirks(usb_quirk_t *a, /* I - First quirk entry */ 1590+ usb_quirk_t *b) /* I - Second quirk entry */ 1591+{ 1592+ int result; /* Result of comparison */ 1593+ 1594+ if ((result = b->vendor_id - a->vendor_id) == 0) 1595+ result = b->product_id - a->product_id; 1596+ 1597+ return (result); 1598+} 1599+ 1600+/* 1601+ * 'print_cb()' - Find a USB printer for printing. 1602+ */ 1603+ 1604+static int /* O - 0 to continue, 1 to stop (found) */ 1605+print_cb(usb_printer_t *printer, /* I - Printer */ 1606+ const char *device_uri, /* I - Device URI */ 1607+ const char *device_id, /* I - IEEE-1284 device ID */ 1608+ const void *data) /* I - User data (make, model, S/N) */ 1609+{ 1610+ char requested_uri[1024], /* Requested URI */ 1611+ *requested_ptr, /* Pointer into requested URI */ 1612+ detected_uri[1024], /* Detected URI */ 1613+ *detected_ptr; /* Pointer into detected URI */ 1614+ 1615+ 1616+ /* 1617+ * If we have an exact match, stop now... 1618+ */ 1619+ 1620+ if (!strcmp((char *)data, device_uri)) 1621+ return (1); 1622+ 1623+ /* 1624+ * Work on copies of the URIs... 1625+ */ 1626+ 1627+ strlcpy(requested_uri, (char *)data, sizeof(requested_uri)); 1628+ strlcpy(detected_uri, device_uri, sizeof(detected_uri)); 1629+ 1630+ /* 1631+ * ohusb-discovered URIs can have an "interface" specification and this 1632+ * never happens for usblp-discovered URIs, so remove the "interface" 1633+ * specification from the URI which we are checking currently. This way a 1634+ * queue for a usblp-discovered printer can now be accessed via ohusb. 1635+ * 1636+ * Similarly, strip "?serial=NNN...NNN" as needed. 1637+ */ 1638+ 1639+ if ((requested_ptr = strstr(requested_uri, "?interface=")) == NULL) 1640+ requested_ptr = strstr(requested_uri, "&interface="); 1641+ if ((detected_ptr = strstr(detected_uri, "?interface=")) == NULL) 1642+ detected_ptr = strstr(detected_uri, "&interface="); 1643+ 1644+ if (!requested_ptr && detected_ptr) 1645+ { 1646+ /* 1647+ * Strip "[?&]interface=nnn" from the detected printer. 1648+ */ 1649+ 1650+ *detected_ptr = '\0'; 1651+ } 1652+ else if (requested_ptr && !detected_ptr) 1653+ { 1654+ /* 1655+ * Strip "[?&]interface=nnn" from the requested printer. 1656+ */ 1657+ 1658+ *requested_ptr = '\0'; 1659+ } 1660+ 1661+ if ((requested_ptr = strstr(requested_uri, "?serial=?")) != NULL) 1662+ { 1663+ /* 1664+ * Strip "?serial=?" from the requested printer. This is a special 1665+ * case, as "?serial=?" means no serial number and not the serial 1666+ * number '?'. This is not covered by the checks below... 1667+ */ 1668+ 1669+ *requested_ptr = '\0'; 1670+ } 1671+ 1672+ if ((requested_ptr = strstr(requested_uri, "?serial=")) == NULL && 1673+ (detected_ptr = strstr(detected_uri, "?serial=")) != NULL) 1674+ { 1675+ /* 1676+ * Strip "?serial=nnn" from the detected printer. 1677+ */ 1678+ 1679+ *detected_ptr = '\0'; 1680+ } 1681+ else if (requested_ptr && !detected_ptr) 1682+ { 1683+ /* 1684+ * Strip "?serial=nnn" from the requested printer. 1685+ */ 1686+ 1687+ *requested_ptr = '\0'; 1688+ } 1689+ 1690+ return (!strcmp(requested_uri, detected_uri)); 1691+} 1692+ 1693+/* 1694+ * 'list_cb()' - List USB printers for discovery. 1695+ */ 1696+ 1697+static int /* O - 0 to continue, 1 to stop */ 1698+list_cb(usb_printer_t *printer, /* I - Printer */ 1699+ const char *device_uri, /* I - Device URI */ 1700+ const char *device_id, /* I - IEEE-1284 device ID */ 1701+ const void *data) /* I - User data (not used) */ 1702+{ 1703+ char make_model[1024]; /* Make and model */ 1704+ 1705+ 1706+ /* 1707+ * Get the device URI and make/model strings... 1708+ */ 1709+ 1710+ if (backendGetMakeModel(device_id, make_model, sizeof(make_model))) 1711+ strlcpy(make_model, "Unknown", sizeof(make_model)); 1712+ 1713+ /* 1714+ * Report the printer... 1715+ */ 1716+ 1717+ char result[10]; 1718+ snprintf(result, sizeof(result), "%04x-%04x", printer->device->idVendor, printer->device->idProduct); 1719+ fprintf(stderr, "DEBUG: list_cb vid-pid:%s.\n", result); 1720+ 1721+ cupsBackendReport("direct", device_uri, make_model, make_model, device_id, result); 1722+ 1723+ /* 1724+ * Keep going... 1725+ */ 1726+ 1727+ return (0); 1728+} 1729+ 1730+/* 1731+ * 'soft_reset()' - Send a soft reset to the device. 1732+ */ 1733+ 1734+static void 1735+soft_reset(void) 1736+{ 1737+ fd_set input_set; /* Input set for select() */ 1738+ struct timeval tv; /* Time value */ 1739+ char buffer[2048]; /* Buffer */ 1740+ struct timespec cond_timeout; /* pthread condition timeout */ 1741+ 1742+ 1743+ /* 1744+ * Send an abort once a second until the I/O lock is released by the main 1745+ * thread... 1746+ */ 1747+ 1748+ pthread_mutex_lock(&g.readwrite_lock_mutex); 1749+ while (g.readwrite_lock) 1750+ { 1751+ gettimeofday(&tv, NULL); 1752+ cond_timeout.tv_sec = tv.tv_sec + 1; 1753+ cond_timeout.tv_nsec = tv.tv_usec * 1000; 1754+ 1755+ while (g.readwrite_lock) 1756+ { 1757+ if (pthread_cond_timedwait(&g.readwrite_lock_cond, 1758+ &g.readwrite_lock_mutex, 1759+ &cond_timeout) != 0) 1760+ break; 1761+ } 1762+ } 1763+ 1764+ g.readwrite_lock = 1; 1765+ pthread_mutex_unlock(&g.readwrite_lock_mutex); 1766+ 1767+ /* 1768+ * Flush bytes waiting on print_fd... 1769+ */ 1770+ 1771+ g.print_bytes = 0; 1772+ 1773+ FD_ZERO(&input_set); 1774+ FD_SET(g.print_fd, &input_set); 1775+ 1776+ tv.tv_sec = 0; 1777+ tv.tv_usec = 0; 1778+ 1779+ while (select(g.print_fd+1, &input_set, NULL, NULL, &tv) > 0) 1780+ if (read(g.print_fd, buffer, sizeof(buffer)) <= 0) 1781+ break; 1782+ 1783+ /* 1784+ * Send the reset... 1785+ */ 1786+ 1787+ soft_reset_printer(g.printer); 1788+ 1789+ /* 1790+ * Release the I/O lock... 1791+ */ 1792+ 1793+ pthread_mutex_lock(&g.readwrite_lock_mutex); 1794+ g.readwrite_lock = 0; 1795+ pthread_cond_signal(&g.readwrite_lock_cond); 1796+ pthread_mutex_unlock(&g.readwrite_lock_mutex); 1797+} 1798+ 1799+ 1800+/* 1801+ * 'soft_reset_printer()' - Do the soft reset request specific to printers 1802+ * 1803+ * This soft reset is specific to the printer device class and is much less 1804+ * invasive than the general USB reset OH_ResetDevice(). Especially it 1805+ * does never happen that the USB addressing and configuration changes. What 1806+ * is actually done is that all buffers get flushed and the bulk IN and OUT 1807+ * pipes get reset to their default states. This clears all stall conditions. 1808+ * See http://cholla.mmto.org/computers/linux/usb/usbprint11.pdf 1809+ */ 1810+ 1811+static int /* O - 0 on success, < 0 on error */ 1812+soft_reset_printer( 1813+ usb_printer_t *printer) /* I - Printer */ 1814+{ 1815+ ohusb_config_descriptor confptr; /* Pointer to current configuration */ 1816+ int interface, /* Interface to reset */ 1817+ errcode; /* Error code */ 1818+ 1819+ 1820+ if (printer->device == NULL) { 1821+ interface = printer->iface; 1822+ } else { 1823+ confptr = printer->device->config[printer->conf]; 1824+ interface = confptr.interface[printer->iface]. 1825+ altsetting[printer->altset].bInterfaceNumber; 1826+ } 1827+ 1828+ ohusb_control_transfer_parameter ctrlParam = { 1829+ OHUSB_REQUEST_TYPE_CLASS | OHUSB_ENDPOINT_OUT | OHUSB_RECIPIENT_OTHER, 1830+ 2, 0, interface, 5000 1831+ }; 1832+ 1833+ if ((errcode = OH_ControlTransferWrite(printer->pipe, &ctrlParam, NULL, 0)) < 0) 1834+ { 1835+ ctrlParam.requestType = OHUSB_REQUEST_TYPE_CLASS | OHUSB_ENDPOINT_OUT | OHUSB_RECIPIENT_INTERFACE; 1836+ errcode = OH_ControlTransferWrite(printer->pipe, &ctrlParam, NULL, 0); 1837+ } 1838+ 1839+ 1840+ return (errcode); 1841+} 1842\ No newline at end of file 1843diff --git a/backend/usb.c b/backend/usb.c 1844index 04c62023..a4dfbc0b 100644 1845--- a/backend/usb.c 1846+++ b/backend/usb.c 1847@@ -43,7 +43,9 @@ int print_device(const char *uri, const char *hostname, 1848 * Include the vendor-specific USB implementation... 1849 */ 1850 1851-#ifdef HAVE_LIBUSB 1852+#ifdef HAVE_OPENHARMONY 1853+# include "usb-oh.c" 1854+#elif defined(HAVE_LIBUSB) 1855 # include "usb-libusb.c" 1856 #elif defined(__APPLE__) 1857 # include "usb-darwin.c" 1858