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