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