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