1diff --git a/backend/usb-oh.c b/backend/usb-oh.c 2new file mode 100644 3index 0000000..3106c11 4--- /dev/null 5+++ b/backend/usb-oh.c 6@@ -0,0 +1,1820 @@ 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+ 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, 0); 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, 0); 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); 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); 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 = %c\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 as needed... 923+ */ 924+ 925+ number1 = confptr.interface[printer->iface].altsetting[printer->altset].bInterfaceNumber; 926+ 927+ if ((errcode = OH_ClaimInterface(printer->pipe, number1, true)) < 0) 928+ { 929+ fprintf(stderr, 930+ "DEBUG: Failed to claim interface %d for %04x:%04x: %s\n", 931+ number1, printer->device->idVendor, printer->device->idProduct, strerror(errno)); 932+ 933+ goto error; 934+ } 935+ 936+ /* 937+ * Set alternate setting, but only if there is more than one option. Some 938+ * printers (e.g., Samsung) don't like usb_set_altinterface. 939+ */ 940+ 941+ if (confptr.interface[printer->iface].num_altsetting > 1) 942+ { 943+ number1 = confptr.interface[printer->iface]. 944+ altsetting[printer->altset].bInterfaceNumber; 945+ number2 = confptr.interface[printer->iface]. 946+ altsetting[printer->altset].bAlternateSetting; 947+ while ((errcode = OH_SetInterface(printer->pipe, number1, number2)) < 0) 948+ { 949+ if (errcode != OHUSB_ERROR_BUSY) 950+ { 951+ fprintf(stderr, 952+ "DEBUG: Failed to set alternate interface %d for %04x:%04x: " 953+ "%s\n", 954+ number2, printer->device->idVendor, printer->device->idProduct, strerror(errno)); 955+ 956+ goto error; 957+ } 958+ } 959+ } 960+ 961+ if (verbose) 962+ fputs("STATE: -connecting-to-device\n", stderr); 963+ 964+ return (0); 965+ 966+ /* 967+ * If we get here, there was a hard error... 968+ */ 969+ 970+ error: 971+ 972+ if (verbose) 973+ fputs("STATE: -connecting-to-device\n", stderr); 974+ 975+ OH_CloseDevice(printer->pipe); 976+ printer->pipe = NULL; 977+ 978+ return (-1); 979+} 980+ 981+/* 982+ * 'get_device_id()' - Get the IEEE-1284 device ID for the printer. 983+ */ 984+ 985+static int /* O - 0 on success, -1 on error */ 986+get_device_id(usb_printer_t *printer, /* I - Printer */ 987+ char *buffer, /* I - String buffer */ 988+ size_t bufsize) /* I - Number of bytes in buffer */ 989+{ 990+ fprintf(stderr, "DEBUG: get_device_id\n"); 991+ 992+ int length; /* Length of device ID */ 993+ 994+ ohusb_control_transfer_parameter ctrlParam = { 995+ OHUSB_REQUEST_TYPE_CLASS | OHUSB_ENDPOINT_IN | OHUSB_RECIPIENT_INTERFACE, 996+ 0, printer->conf, (printer->iface << 8) | printer->altset, 5000 997+ }; 998+ 999+ if (OH_ControlTransferRead(printer->pipe, &ctrlParam, (unsigned char *)buffer, bufsize) < 0) 1000+ { 1001+ *buffer = '\0'; 1002+ return (-1); 1003+ } 1004+ 1005+ /* 1006+ * Extract the length of the device ID string from the first two 1007+ * bytes. The 1284 spec says the length is stored MSB first... 1008+ */ 1009+ 1010+ length = (int)((((unsigned)buffer[0] & 255) << 8) | ((unsigned)buffer[1] & 255)); 1011+ 1012+ /* 1013+ * Check to see if the length is larger than our buffer or less than 14 bytes 1014+ * (the minimum valid device ID is "MFG:x;MDL:y;" with 2 bytes for the length). 1015+ * 1016+ * If the length is out-of-range, assume that the vendor incorrectly 1017+ * implemented the 1284 spec and re-read the length as LSB first,.. 1018+ */ 1019+ 1020+ if (length > bufsize || length < 14) 1021+ length = (int)((((unsigned)buffer[1] & 255) << 8) | ((unsigned)buffer[0] & 255)); 1022+ 1023+ if (length > bufsize) 1024+ length = bufsize; 1025+ 1026+ if (length < 14) 1027+ { 1028+ /* 1029+ * Invalid device ID, clear it! 1030+ */ 1031+ 1032+ *buffer = '\0'; 1033+ fprintf(stderr, "DEBUG: get_device_id Invalid device ID\n"); 1034+ return (-1); 1035+ } 1036+ 1037+ length -= 2; 1038+ fprintf(stderr, "DEBUG: get_device_id length = %d\n", length); 1039+ 1040+ /* 1041+ * Copy the device ID text to the beginning of the buffer and 1042+ * nul-terminate. 1043+ */ 1044+ 1045+ memmove(buffer, buffer + 2, (size_t)length); 1046+ buffer[length] = '\0'; 1047+ 1048+ return (0); 1049+} 1050+ 1051+/* 1052+ * 'make_device_uri()' - Create a device URI for a USB printer. 1053+ */ 1054+ 1055+static char * /* O - Device URI */ 1056+make_device_uri( 1057+ usb_printer_t *printer, /* I - Printer */ 1058+ const char *device_id, /* I - IEEE-1284 device ID */ 1059+ char *uri, /* I - Device URI buffer */ 1060+ size_t uri_size) /* I - Size of device URI buffer */ 1061+{ 1062+ char options[1024]; /* Device URI options */ 1063+ int num_values; /* Number of 1284 parameters */ 1064+ cups_option_t *values; /* 1284 parameters */ 1065+ const char *mfg, /* Manufacturer */ 1066+ *mdl, /* Model */ 1067+ *des = NULL, /* Description */ 1068+ *sern = NULL; /* Serial number */ 1069+ size_t mfglen; /* Length of manufacturer string */ 1070+ char tempmdl[256], /* Temporary model string */ 1071+ tempmfg[256], /* Temporary manufacturer string */ 1072+ tempsern[256], /* Temporary serial number string */ 1073+ *tempptr; /* Pointer into temp string */ 1074+ 1075+ fprintf(stderr, "DEBUG: make_device_uri\n"); 1076+ 1077+ /* 1078+ * Get the make, model, and serial numbers... 1079+ */ 1080+ 1081+ num_values = _cupsGet1284Values(device_id, &values); 1082+ 1083+ if (printer->device != NULL && printer->device->iSerialNumber) 1084+ { 1085+ // Try getting the serial number from the device itself... 1086+ int length = OH_GetStringDescriptor(printer->pipe, printer->device->iSerialNumber, (unsigned char *)tempsern, sizeof(tempsern) - 1); 1087+ if (length > 0) 1088+ { 1089+ tempsern[length] = '\0'; 1090+ sern = tempsern; 1091+ } 1092+ else 1093+ fputs("DEBUG2: iSerialNumber could not be read.\n", stderr); 1094+ } 1095+ else 1096+ fputs("DEBUG2: iSerialNumber is not present.\n", stderr); 1097+ 1098+ if ((mfg = cupsGetOption("MANUFACTURER", num_values, values)) == NULL) 1099+ { 1100+ if ((mfg = cupsGetOption("MFG", num_values, values)) == NULL && printer->device->iManufacturer) 1101+ { 1102+ int length = OH_GetStringDescriptor(printer->pipe, printer->device->iManufacturer, (unsigned char *)tempmfg, sizeof(tempmfg) - 1); 1103+ if (length > 0) 1104+ { 1105+ tempmfg[length] = '\0'; 1106+ mfg = tempmfg; 1107+ } 1108+ } 1109+ } 1110+ 1111+ if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL) 1112+ { 1113+ if ((mdl = cupsGetOption("MDL", num_values, values)) == NULL && printer->device->iProduct) 1114+ { 1115+ int length = OH_GetStringDescriptor(printer->pipe, printer->device->iProduct, (unsigned char *)tempmdl, sizeof(tempmdl) - 1); 1116+ if (length > 0) 1117+ { 1118+ tempmdl[length] = '\0'; 1119+ mdl = tempmdl; 1120+ } 1121+ } 1122+ } 1123+ 1124+ /* 1125+ * To maintain compatibility with the original character device backend on 1126+ * Linux and *BSD, map manufacturer names... 1127+ */ 1128+ 1129+ if (mfg) 1130+ { 1131+ if (!_cups_strcasecmp(mfg, "Hewlett-Packard")) 1132+ mfg = "HP"; 1133+ else if (!_cups_strcasecmp(mfg, "Lexmark International")) 1134+ mfg = "Lexmark"; 1135+ } 1136+ else 1137+ { 1138+ /* 1139+ * No manufacturer? Use the model string or description... 1140+ */ 1141+ 1142+ if (mdl) 1143+ _ppdNormalizeMakeAndModel(mdl, tempmfg, sizeof(tempmfg)); 1144+ else if ((des = cupsGetOption("DESCRIPTION", num_values, values)) != NULL || 1145+ (des = cupsGetOption("DES", num_values, values)) != NULL) 1146+ _ppdNormalizeMakeAndModel(des, tempmfg, sizeof(tempmfg)); 1147+ else 1148+ strlcpy(tempmfg, "Unknown", sizeof(tempmfg)); 1149+ 1150+ if ((tempptr = strchr(tempmfg, ' ')) != NULL) 1151+ *tempptr = '\0'; 1152+ 1153+ mfg = tempmfg; 1154+ } 1155+ 1156+ if (!mdl) 1157+ { 1158+ /* 1159+ * No model? Use description... 1160+ */ 1161+ if (des) 1162+ mdl = des; /* We remove the manufacturer name below */ 1163+ else if (!strncasecmp(mfg, "Unknown", 7)) 1164+ mdl = "Printer"; 1165+ else 1166+ mdl = "Unknown Model"; 1167+ } 1168+ 1169+ mfglen = strlen(mfg); 1170+ 1171+ if (!strncasecmp(mdl, mfg, mfglen) && _cups_isspace(mdl[mfglen])) 1172+ { 1173+ mdl += mfglen + 1; 1174+ 1175+ while (_cups_isspace(*mdl)) 1176+ mdl ++; 1177+ } 1178+ 1179+ /* 1180+ * Generate the device URI from the manufacturer, model, serial number, 1181+ * and interface number... 1182+ */ 1183+ 1184+ if (sern) 1185+ { 1186+ if (printer->iface > 0) 1187+ snprintf(options, sizeof(options), "?serial=%s&interface=%d", sern, printer->iface); 1188+ else 1189+ snprintf(options, sizeof(options), "?serial=%s", sern); 1190+ } 1191+ else if (printer->iface > 0) 1192+ snprintf(options, sizeof(options), "?interface=%d", printer->iface); 1193+ else 1194+ options[0] = '\0'; 1195+ 1196+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, uri_size, "usb", NULL, mfg, 0, "/%s%s", mdl, options); 1197+ 1198+ fprintf(stderr, "DEBUG2: make_device_uri sern=\"%s\", mfg=\"%s\", mdl=\"%s\"\n", sern, mfg, mdl); 1199+ 1200+ cupsFreeOptions(num_values, values); 1201+ 1202+ return (uri); 1203+} 1204+ 1205+/* 1206+ * 'close_device()' - Close the connection to the USB printer. 1207+ */ 1208+ 1209+static int /* I - 0 on success, -1 on failure */ 1210+close_device(usb_printer_t *printer) /* I - Printer */ 1211+{ 1212+ ohusb_config_descriptor confptr; /* Pointer to current configuration */ 1213+ 1214+ if (printer->pipe) 1215+ { 1216+ /* 1217+ * Release interfaces before closing so that we know all data is written 1218+ * to the device... 1219+ */ 1220+ 1221+ int errcode; /* Return value of ohusb function */ 1222+ int number1, /* Interface number */ 1223+ number2; /* Configuration number */ 1224+ 1225+ if (printer->device != NULL && printer->device->config != NULL) 1226+ { 1227+ confptr = printer->device->config[printer->conf]; 1228+ number1 = confptr.interface[printer->iface]. 1229+ altsetting[printer->altset].bInterfaceNumber; 1230+ OH_ReleaseInterface(printer->pipe, number1); 1231+ 1232+ number2 = confptr.iConfiguration; 1233+ 1234+ /* 1235+ * If we have changed the configuration from one valid configuration 1236+ * to another, restore the old one 1237+ */ 1238+ if (printer->origconf > 0 && printer->origconf != number2) 1239+ { 1240+ fprintf(stderr, "DEBUG: Restoring USB device configuration: %d -> %d\n", 1241+ number2, printer->origconf); 1242+ if ((errcode = OH_SetConfiguration(printer->pipe, printer->origconf)) < 0) 1243+ { 1244+ fprintf(stderr, 1245+ "DEBUG: Failed to set configuration %d for %04x:%04x\n", 1246+ printer->origconf, printer->device->idVendor, printer->device->idProduct); 1247+ } 1248+ } 1249+ } 1250+ else 1251+ fprintf(stderr, 1252+ "DEBUG: Failed to get configuration descriptor %d\n", 1253+ printer->conf); 1254+ 1255+ /* 1256+ * Close the interface and return... 1257+ */ 1258+ 1259+ if (OH_CloseDevice(printer->pipe) == OHUSB_SUCCESS) 1260+ printer->pipe = NULL; 1261+ } 1262+ 1263+ return (0); 1264+} 1265+ 1266+/* 1267+ * 'read_thread()' - Thread to read the backchannel data on. 1268+ */ 1269+ 1270+static void *read_thread(void *reference) 1271+{ 1272+ unsigned char readbuffer[512]; 1273+ int rbytes; 1274+ int readstatus; 1275+ ohusb_transfer_pipe tpipe = { 1276+ g.printer->iface, 1277+ g.printer->read_endp 1278+ }; 1279+ 1280+ 1281+ (void)reference; 1282+ 1283+ do 1284+ { 1285+ /* 1286+ * Try reading from the OUT (to host) endpoint... 1287+ */ 1288+ 1289+ rbytes = sizeof(readbuffer); 1290+ readstatus = OH_BulkTransferRead(g.printer->pipe, 1291+ &tpipe, readbuffer, rbytes, &rbytes); 1292+ if (readstatus == OHUSB_SUCCESS && rbytes > 0) 1293+ { 1294+ fprintf(stderr, "DEBUG: Read %d bytes of back-channel data...\n", (int)rbytes); 1295+ cupsBackChannelWrite((const char *)readbuffer, (size_t)rbytes, 1.0); 1296+ } 1297+ else 1298+ fprintf(stderr, "DEBUG: Got USB transaction error during read, errorcode=%d\n", readstatus); 1299+ 1300+ /* 1301+ * Make sure this loop executes no more than once every 250 miliseconds... 1302+ */ 1303+ 1304+ if ((readstatus != OHUSB_SUCCESS || rbytes == 0) && (g.wait_eof || !g.read_thread_stop)) 1305+ usleep(250000); 1306+ } 1307+ while (g.wait_eof || !g.read_thread_stop); 1308+ 1309+ /* 1310+ * Let the main thread know that we have completed the read thread... 1311+ */ 1312+ 1313+ pthread_mutex_lock(&g.read_thread_mutex); 1314+ g.read_thread_done = 1; 1315+ pthread_cond_signal(&g.read_thread_cond); 1316+ pthread_mutex_unlock(&g.read_thread_mutex); 1317+ 1318+ return (NULL); 1319+} 1320+ 1321+/* 1322+ * 'sidechannel_thread()' - Handle side-channel requests. 1323+ */ 1324+ 1325+static void* 1326+sidechannel_thread(void *reference) 1327+{ 1328+ cups_sc_command_t command; /* Request command */ 1329+ cups_sc_status_t status; /* Request/response status */ 1330+ char data[2048]; /* Request/response data */ 1331+ int datalen; /* Request/response data size */ 1332+ 1333+ 1334+ (void)reference; 1335+ 1336+ do 1337+ { 1338+ datalen = sizeof(data); 1339+ 1340+ if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0)) 1341+ { 1342+ if (status == CUPS_SC_STATUS_TIMEOUT) 1343+ continue; 1344+ else 1345+ break; 1346+ } 1347+ 1348+ switch (command) 1349+ { 1350+ case CUPS_SC_CMD_SOFT_RESET: /* Do a soft reset */ 1351+ fputs("DEBUG: CUPS_SC_CMD_SOFT_RESET received from driver...\n", stderr); 1352+ 1353+ soft_reset(); 1354+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, NULL, 0, 1.0); 1355+ fputs("DEBUG: Returning status CUPS_STATUS_OK with no bytes...\n", 1356+ stderr); 1357+ break; 1358+ 1359+ case CUPS_SC_CMD_DRAIN_OUTPUT: /* Drain all pending output */ 1360+ fputs("DEBUG: CUPS_SC_CMD_DRAIN_OUTPUT received from driver...\n", stderr); 1361+ 1362+ g.drain_output = 1; 1363+ break; 1364+ 1365+ case CUPS_SC_CMD_GET_BIDI: /* Is the connection bidirectional? */ 1366+ fputs("DEBUG: CUPS_SC_CMD_GET_BIDI received from driver...\n", stderr); 1367+ 1368+ data[0] = (g.printer->protocol >= 2 ? 1 : 0); 1369+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0); 1370+ 1371+ fprintf(stderr, 1372+ "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n", 1373+ data[0]); 1374+ break; 1375+ 1376+ case CUPS_SC_CMD_GET_DEVICE_ID: /* Return IEEE-1284 device ID */ 1377+ fputs("DEBUG: CUPS_SC_CMD_GET_DEVICE_ID received from driver...\n", stderr); 1378+ 1379+ datalen = sizeof(data); 1380+ if (get_device_id(g.printer, data, sizeof(data))) 1381+ { 1382+ status = CUPS_SC_STATUS_IO_ERROR; 1383+ datalen = 0; 1384+ } 1385+ else 1386+ { 1387+ status = CUPS_SC_STATUS_OK; 1388+ datalen = strlen(data); 1389+ } 1390+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, datalen, 1.0); 1391+ 1392+ if (datalen < sizeof(data)) 1393+ data[datalen] = '\0'; 1394+ else 1395+ data[sizeof(data) - 1] = '\0'; 1396+ 1397+ fprintf(stderr, 1398+ "DEBUG: Returning CUPS_SC_STATUS_OK with %d bytes (%s)...\n", 1399+ datalen, data); 1400+ break; 1401+ 1402+ case CUPS_SC_CMD_GET_STATE: /* Return device state */ 1403+ fputs("DEBUG: CUPS_SC_CMD_GET_STATE received from driver...\n", stderr); 1404+ 1405+ data[0] = CUPS_SC_STATE_ONLINE; 1406+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0); 1407+ 1408+ fprintf(stderr, 1409+ "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n", 1410+ data[0]); 1411+ break; 1412+ 1413+ case CUPS_SC_CMD_GET_CONNECTED: /* Return whether device is 1414+ connected */ 1415+ fputs("DEBUG: CUPS_SC_CMD_GET_CONNECTED received from driver...\n", stderr); 1416+ 1417+ data[0] = (g.printer->device ? 1 : 0); 1418+ cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0); 1419+ 1420+ fprintf(stderr, 1421+ "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n", 1422+ data[0]); 1423+ break; 1424+ 1425+ default: 1426+ fprintf(stderr, "DEBUG: Unknown side-channel command (%d) received " 1427+ "from driver...\n", command); 1428+ 1429+ cupsSideChannelWrite(command, CUPS_SC_STATUS_NOT_IMPLEMENTED, NULL, 0, 1.0); 1430+ 1431+ fputs("DEBUG: Returned CUPS_SC_STATUS_NOT_IMPLEMENTED with no bytes...\n", stderr); 1432+ break; 1433+ } 1434+ } 1435+ while (!g.sidechannel_thread_stop); 1436+ 1437+ pthread_mutex_lock(&g.sidechannel_thread_mutex); 1438+ g.sidechannel_thread_done = 1; 1439+ pthread_cond_signal(&g.sidechannel_thread_cond); 1440+ pthread_mutex_unlock(&g.sidechannel_thread_mutex); 1441+ 1442+ return (NULL); 1443+} 1444+ 1445+/* 1446+ * 'load_quirks()' - Load all quirks files in the /usr/share/cups/usb directory. 1447+ */ 1448+ 1449+static void 1450+load_quirks(void) 1451+{ 1452+ const char *datadir; /* CUPS_DATADIR environment variable */ 1453+ char filename[1024], /* Filename */ 1454+ line[1024]; /* Line from file */ 1455+ cups_dir_t *dir; /* Directory */ 1456+ cups_dentry_t *dent; /* Directory entry */ 1457+ cups_file_t *fp; /* Quirks file */ 1458+ usb_quirk_t *quirk; /* New quirk */ 1459+ 1460+ 1461+ all_quirks = cupsArrayNew((cups_array_func_t)compare_quirks, NULL); 1462+ 1463+ if ((datadir = getenv("CUPS_DATADIR")) == NULL) 1464+ datadir = CUPS_DATADIR; 1465+ 1466+ snprintf(filename, sizeof(filename), "%s/usb", datadir); 1467+ if ((dir = cupsDirOpen(filename)) == NULL) 1468+ { 1469+ perror(filename); 1470+ return; 1471+ } 1472+ 1473+ fprintf(stderr, "DEBUG: Loading USB quirks from \"%s\".\n", filename); 1474+ 1475+ while ((dent = cupsDirRead(dir)) != NULL) 1476+ { 1477+ if (!S_ISREG(dent->fileinfo.st_mode)) 1478+ continue; 1479+ 1480+ snprintf(filename, sizeof(filename), "%s/usb/%s", datadir, dent->filename); 1481+ if ((fp = cupsFileOpen(filename, "r")) == NULL) 1482+ { 1483+ perror(filename); 1484+ continue; 1485+ } 1486+ 1487+ while (cupsFileGets(fp, line, sizeof(line))) 1488+ { 1489+ /* 1490+ * Skip blank and comment lines... 1491+ */ 1492+ 1493+ if (line[0] == '#' || !line[0]) 1494+ continue; 1495+ 1496+ /* 1497+ * Add a quirk... 1498+ */ 1499+ 1500+ if ((quirk = calloc(1, sizeof(usb_quirk_t))) == NULL) 1501+ { 1502+ perror("DEBUG: Unable to allocate memory for quirk"); 1503+ break; 1504+ } 1505+ 1506+ if (sscanf(line, "%x%x", &quirk->vendor_id, &quirk->product_id) < 1) 1507+ { 1508+ fprintf(stderr, "DEBUG: Bad line: %s\n", line); 1509+ free(quirk); 1510+ continue; 1511+ } 1512+ 1513+ if (strstr(line, " blacklist")) 1514+ quirk->quirks |= USB_QUIRK_BLACKLIST; 1515+ 1516+ if (strstr(line, " delay-close")) 1517+ quirk->quirks |= USB_QUIRK_DELAY_CLOSE; 1518+ 1519+ if (strstr(line, " no-reattach")) 1520+ quirk->quirks |= USB_QUIRK_NO_REATTACH; 1521+ 1522+ if (strstr(line, " soft-reset")) 1523+ quirk->quirks |= USB_QUIRK_SOFT_RESET; 1524+ 1525+ if (strstr(line, " unidir")) 1526+ quirk->quirks |= USB_QUIRK_UNIDIR; 1527+ 1528+ if (strstr(line, " usb-init")) 1529+ quirk->quirks |= USB_QUIRK_USB_INIT; 1530+ 1531+ if (strstr(line, " vendor-class")) 1532+ quirk->quirks |= USB_QUIRK_VENDOR_CLASS; 1533+ 1534+ cupsArrayAdd(all_quirks, quirk); 1535+ } 1536+ 1537+ cupsFileClose(fp); 1538+ } 1539+ 1540+ fprintf(stderr, "DEBUG: Loaded %d quirks.\n", cupsArrayCount(all_quirks)); 1541+ 1542+ cupsDirClose(dir); 1543+} 1544+ 1545+/* 1546+ * 'find_quirks()' - Find the quirks for the given printer, if any. 1547+ * 1548+ * First looks for an exact match, then looks for the vendor ID wildcard match. 1549+ */ 1550+ 1551+static unsigned /* O - Quirks flags */ 1552+find_quirks(int vendor_id, /* I - Vendor ID */ 1553+ int product_id) /* I - Product ID */ 1554+{ 1555+ usb_quirk_t key, /* Search key */ 1556+ *match; /* Matching quirk entry */ 1557+ 1558+ 1559+ key.vendor_id = vendor_id; 1560+ key.product_id = product_id; 1561+ 1562+ if ((match = cupsArrayFind(all_quirks, &key)) != NULL) 1563+ return (match->quirks); 1564+ 1565+ key.product_id = 0; 1566+ 1567+ if ((match = cupsArrayFind(all_quirks, &key)) != NULL) 1568+ return (match->quirks); 1569+ 1570+ return (USB_QUIRK_WHITELIST); 1571+} 1572+ 1573+/* 1574+ * 'compare_quirks()' - Compare two quirks entries. 1575+ */ 1576+ 1577+static int /* O - Result of comparison */ 1578+compare_quirks(usb_quirk_t *a, /* I - First quirk entry */ 1579+ usb_quirk_t *b) /* I - Second quirk entry */ 1580+{ 1581+ int result; /* Result of comparison */ 1582+ 1583+ if ((result = b->vendor_id - a->vendor_id) == 0) 1584+ result = b->product_id - a->product_id; 1585+ 1586+ return (result); 1587+} 1588+ 1589+/* 1590+ * 'print_cb()' - Find a USB printer for printing. 1591+ */ 1592+ 1593+static int /* O - 0 to continue, 1 to stop (found) */ 1594+print_cb(usb_printer_t *printer, /* I - Printer */ 1595+ const char *device_uri, /* I - Device URI */ 1596+ const char *device_id, /* I - IEEE-1284 device ID */ 1597+ const void *data) /* I - User data (make, model, S/N) */ 1598+{ 1599+ char requested_uri[1024], /* Requested URI */ 1600+ *requested_ptr, /* Pointer into requested URI */ 1601+ detected_uri[1024], /* Detected URI */ 1602+ *detected_ptr; /* Pointer into detected URI */ 1603+ 1604+ 1605+ /* 1606+ * If we have an exact match, stop now... 1607+ */ 1608+ 1609+ if (!strcmp((char *)data, device_uri)) 1610+ return (1); 1611+ 1612+ /* 1613+ * Work on copies of the URIs... 1614+ */ 1615+ 1616+ strlcpy(requested_uri, (char *)data, sizeof(requested_uri)); 1617+ strlcpy(detected_uri, device_uri, sizeof(detected_uri)); 1618+ 1619+ /* 1620+ * ohusb-discovered URIs can have an "interface" specification and this 1621+ * never happens for usblp-discovered URIs, so remove the "interface" 1622+ * specification from the URI which we are checking currently. This way a 1623+ * queue for a usblp-discovered printer can now be accessed via ohusb. 1624+ * 1625+ * Similarly, strip "?serial=NNN...NNN" as needed. 1626+ */ 1627+ 1628+ if ((requested_ptr = strstr(requested_uri, "?interface=")) == NULL) 1629+ requested_ptr = strstr(requested_uri, "&interface="); 1630+ if ((detected_ptr = strstr(detected_uri, "?interface=")) == NULL) 1631+ detected_ptr = strstr(detected_uri, "&interface="); 1632+ 1633+ if (!requested_ptr && detected_ptr) 1634+ { 1635+ /* 1636+ * Strip "[?&]interface=nnn" from the detected printer. 1637+ */ 1638+ 1639+ *detected_ptr = '\0'; 1640+ } 1641+ else if (requested_ptr && !detected_ptr) 1642+ { 1643+ /* 1644+ * Strip "[?&]interface=nnn" from the requested printer. 1645+ */ 1646+ 1647+ *requested_ptr = '\0'; 1648+ } 1649+ 1650+ if ((requested_ptr = strstr(requested_uri, "?serial=?")) != NULL) 1651+ { 1652+ /* 1653+ * Strip "?serial=?" from the requested printer. This is a special 1654+ * case, as "?serial=?" means no serial number and not the serial 1655+ * number '?'. This is not covered by the checks below... 1656+ */ 1657+ 1658+ *requested_ptr = '\0'; 1659+ } 1660+ 1661+ if ((requested_ptr = strstr(requested_uri, "?serial=")) == NULL && 1662+ (detected_ptr = strstr(detected_uri, "?serial=")) != NULL) 1663+ { 1664+ /* 1665+ * Strip "?serial=nnn" from the detected printer. 1666+ */ 1667+ 1668+ *detected_ptr = '\0'; 1669+ } 1670+ else if (requested_ptr && !detected_ptr) 1671+ { 1672+ /* 1673+ * Strip "?serial=nnn" from the requested printer. 1674+ */ 1675+ 1676+ *requested_ptr = '\0'; 1677+ } 1678+ 1679+ return (!strcmp(requested_uri, detected_uri)); 1680+} 1681+ 1682+/* 1683+ * 'list_cb()' - List USB printers for discovery. 1684+ */ 1685+ 1686+static int /* O - 0 to continue, 1 to stop */ 1687+list_cb(usb_printer_t *printer, /* I - Printer */ 1688+ const char *device_uri, /* I - Device URI */ 1689+ const char *device_id, /* I - IEEE-1284 device ID */ 1690+ const void *data) /* I - User data (not used) */ 1691+{ 1692+ char make_model[1024]; /* Make and model */ 1693+ 1694+ 1695+ /* 1696+ * Get the device URI and make/model strings... 1697+ */ 1698+ 1699+ if (backendGetMakeModel(device_id, make_model, sizeof(make_model))) 1700+ strlcpy(make_model, "Unknown", sizeof(make_model)); 1701+ 1702+ /* 1703+ * Report the printer... 1704+ */ 1705+ 1706+ cupsBackendReport("direct", device_uri, make_model, make_model, device_id, NULL); 1707+ 1708+ /* 1709+ * Keep going... 1710+ */ 1711+ 1712+ return (0); 1713+} 1714+ 1715+/* 1716+ * 'soft_reset()' - Send a soft reset to the device. 1717+ */ 1718+ 1719+static void 1720+soft_reset(void) 1721+{ 1722+ fd_set input_set; /* Input set for select() */ 1723+ struct timeval tv; /* Time value */ 1724+ char buffer[2048]; /* Buffer */ 1725+ struct timespec cond_timeout; /* pthread condition timeout */ 1726+ 1727+ 1728+ /* 1729+ * Send an abort once a second until the I/O lock is released by the main 1730+ * thread... 1731+ */ 1732+ 1733+ pthread_mutex_lock(&g.readwrite_lock_mutex); 1734+ while (g.readwrite_lock) 1735+ { 1736+ gettimeofday(&tv, NULL); 1737+ cond_timeout.tv_sec = tv.tv_sec + 1; 1738+ cond_timeout.tv_nsec = tv.tv_usec * 1000; 1739+ 1740+ while (g.readwrite_lock) 1741+ { 1742+ if (pthread_cond_timedwait(&g.readwrite_lock_cond, 1743+ &g.readwrite_lock_mutex, 1744+ &cond_timeout) != 0) 1745+ break; 1746+ } 1747+ } 1748+ 1749+ g.readwrite_lock = 1; 1750+ pthread_mutex_unlock(&g.readwrite_lock_mutex); 1751+ 1752+ /* 1753+ * Flush bytes waiting on print_fd... 1754+ */ 1755+ 1756+ g.print_bytes = 0; 1757+ 1758+ FD_ZERO(&input_set); 1759+ FD_SET(g.print_fd, &input_set); 1760+ 1761+ tv.tv_sec = 0; 1762+ tv.tv_usec = 0; 1763+ 1764+ while (select(g.print_fd+1, &input_set, NULL, NULL, &tv) > 0) 1765+ if (read(g.print_fd, buffer, sizeof(buffer)) <= 0) 1766+ break; 1767+ 1768+ /* 1769+ * Send the reset... 1770+ */ 1771+ 1772+ soft_reset_printer(g.printer); 1773+ 1774+ /* 1775+ * Release the I/O lock... 1776+ */ 1777+ 1778+ pthread_mutex_lock(&g.readwrite_lock_mutex); 1779+ g.readwrite_lock = 0; 1780+ pthread_cond_signal(&g.readwrite_lock_cond); 1781+ pthread_mutex_unlock(&g.readwrite_lock_mutex); 1782+} 1783+ 1784+ 1785+/* 1786+ * 'soft_reset_printer()' - Do the soft reset request specific to printers 1787+ * 1788+ * This soft reset is specific to the printer device class and is much less 1789+ * invasive than the general USB reset OH_ResetDevice(). Especially it 1790+ * does never happen that the USB addressing and configuration changes. What 1791+ * is actually done is that all buffers get flushed and the bulk IN and OUT 1792+ * pipes get reset to their default states. This clears all stall conditions. 1793+ * See http://cholla.mmto.org/computers/linux/usb/usbprint11.pdf 1794+ */ 1795+ 1796+static int /* O - 0 on success, < 0 on error */ 1797+soft_reset_printer( 1798+ usb_printer_t *printer) /* I - Printer */ 1799+{ 1800+ ohusb_config_descriptor confptr; /* Pointer to current configuration */ 1801+ int interface, /* Interface to reset */ 1802+ errcode; /* Error code */ 1803+ 1804+ 1805+ if (printer->device == NULL) { 1806+ interface = printer->iface; 1807+ } else { 1808+ confptr = printer->device->config[printer->conf]; 1809+ interface = confptr.interface[printer->iface]. 1810+ altsetting[printer->altset].bInterfaceNumber; 1811+ } 1812+ 1813+ ohusb_control_transfer_parameter ctrlParam = { 1814+ OHUSB_REQUEST_TYPE_CLASS | OHUSB_ENDPOINT_OUT | OHUSB_RECIPIENT_OTHER, 1815+ 2, 0, interface, 5000 1816+ }; 1817+ 1818+ if ((errcode = OH_ControlTransferWrite(printer->pipe, &ctrlParam, NULL, 0)) < 0) 1819+ { 1820+ ctrlParam.requestType = OHUSB_REQUEST_TYPE_CLASS | OHUSB_ENDPOINT_OUT | OHUSB_RECIPIENT_INTERFACE; 1821+ errcode = OH_ControlTransferWrite(printer->pipe, &ctrlParam, NULL, 0); 1822+ } 1823+ 1824+ 1825+ return (errcode); 1826+} 1827\ No newline at end of file 1828diff --git a/backend/usb.c b/backend/usb.c 1829index e1b2c03..50c1bc3 100644 1830--- a/backend/usb.c 1831+++ b/backend/usb.c 1832@@ -42,7 +42,9 @@ int print_device(const char *uri, const char *hostname, 1833 * Include the vendor-specific USB implementation... 1834 */ 1835 1836-#ifdef HAVE_LIBUSB 1837+#ifdef HAVE_OPENHARMONY 1838+# include "usb-oh.c" 1839+#elif defined(HAVE_LIBUSB) 1840 # include "usb-libusb.c" 1841 #elif defined(__APPLE__) 1842 # include "usb-darwin.c" 1843