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