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