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