xref: /aosp_15_r20/external/libcups/backend/usb-darwin.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker  * USB backend for macOS.
3*5e7646d2SAndroid Build Coastguard Worker  *
4*5e7646d2SAndroid Build Coastguard Worker  * Copyright © 2005-2021 Apple Inc. All rights reserved.
5*5e7646d2SAndroid Build Coastguard Worker  *
6*5e7646d2SAndroid Build Coastguard Worker  * IMPORTANT:  This Apple software is supplied to you by Apple Computer,
7*5e7646d2SAndroid Build Coastguard Worker  * Inc. ("Apple") in consideration of your agreement to the following
8*5e7646d2SAndroid Build Coastguard Worker  * terms, and your use, installation, modification or redistribution of
9*5e7646d2SAndroid Build Coastguard Worker  * this Apple software constitutes acceptance of these terms.  If you do
10*5e7646d2SAndroid Build Coastguard Worker  * not agree with these terms, please do not use, install, modify or
11*5e7646d2SAndroid Build Coastguard Worker  * redistribute this Apple software.
12*5e7646d2SAndroid Build Coastguard Worker  *
13*5e7646d2SAndroid Build Coastguard Worker  * In consideration of your agreement to abide by the following terms, and
14*5e7646d2SAndroid Build Coastguard Worker  * subject to these terms, Apple grants you a personal, non-exclusive
15*5e7646d2SAndroid Build Coastguard Worker  * license, under Apple's copyrights in this original Apple software (the
16*5e7646d2SAndroid Build Coastguard Worker  * "Apple Software"), to use, reproduce, modify and redistribute the Apple
17*5e7646d2SAndroid Build Coastguard Worker  * Software, with or without modifications, in source and/or binary forms;
18*5e7646d2SAndroid Build Coastguard Worker  * provided that if you redistribute the Apple Software in its entirety and
19*5e7646d2SAndroid Build Coastguard Worker  * without modifications, you must retain this notice and the following
20*5e7646d2SAndroid Build Coastguard Worker  * text and disclaimers in all such redistributions of the Apple Software.
21*5e7646d2SAndroid Build Coastguard Worker  * Neither the name, trademarks, service marks or logos of Apple Computer,
22*5e7646d2SAndroid Build Coastguard Worker  * Inc. may be used to endorse or promote products derived from the Apple
23*5e7646d2SAndroid Build Coastguard Worker  * Software without specific prior written permission from Apple.  Except
24*5e7646d2SAndroid Build Coastguard Worker  * as expressly stated in this notice, no other rights or licenses, express
25*5e7646d2SAndroid Build Coastguard Worker  * or implied, are granted by Apple herein, including but not limited to
26*5e7646d2SAndroid Build Coastguard Worker  * any patent rights that may be infringed by your derivative works or by
27*5e7646d2SAndroid Build Coastguard Worker  * other works in which the Apple Software may be incorporated.
28*5e7646d2SAndroid Build Coastguard Worker  *
29*5e7646d2SAndroid Build Coastguard Worker  * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
30*5e7646d2SAndroid Build Coastguard Worker  * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
31*5e7646d2SAndroid Build Coastguard Worker  * THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
32*5e7646d2SAndroid Build Coastguard Worker  * FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
33*5e7646d2SAndroid Build Coastguard Worker  * OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
34*5e7646d2SAndroid Build Coastguard Worker  *
35*5e7646d2SAndroid Build Coastguard Worker  * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
36*5e7646d2SAndroid Build Coastguard Worker  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37*5e7646d2SAndroid Build Coastguard Worker  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38*5e7646d2SAndroid Build Coastguard Worker  * INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
39*5e7646d2SAndroid Build Coastguard Worker  * MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
40*5e7646d2SAndroid Build Coastguard Worker  * AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
41*5e7646d2SAndroid Build Coastguard Worker  * STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
42*5e7646d2SAndroid Build Coastguard Worker  * POSSIBILITY OF SUCH DAMAGE.
43*5e7646d2SAndroid Build Coastguard Worker  */
44*5e7646d2SAndroid Build Coastguard Worker 
45*5e7646d2SAndroid Build Coastguard Worker /*
46*5e7646d2SAndroid Build Coastguard Worker  * Include necessary headers.
47*5e7646d2SAndroid Build Coastguard Worker  */
48*5e7646d2SAndroid Build Coastguard Worker 
49*5e7646d2SAndroid Build Coastguard Worker #include <stdio.h>
50*5e7646d2SAndroid Build Coastguard Worker #include <stdlib.h>
51*5e7646d2SAndroid Build Coastguard Worker #include <errno.h>
52*5e7646d2SAndroid Build Coastguard Worker #include <signal.h>
53*5e7646d2SAndroid Build Coastguard Worker #include <fcntl.h>
54*5e7646d2SAndroid Build Coastguard Worker #include <termios.h>
55*5e7646d2SAndroid Build Coastguard Worker #include <unistd.h>
56*5e7646d2SAndroid Build Coastguard Worker #include <sys/stat.h>
57*5e7646d2SAndroid Build Coastguard Worker #include <sys/sysctl.h>
58*5e7646d2SAndroid Build Coastguard Worker #include <libgen.h>
59*5e7646d2SAndroid Build Coastguard Worker #include <mach/mach.h>
60*5e7646d2SAndroid Build Coastguard Worker #include <mach/mach_error.h>
61*5e7646d2SAndroid Build Coastguard Worker #include <mach/mach_time.h>
62*5e7646d2SAndroid Build Coastguard Worker #include <cups/debug-private.h>
63*5e7646d2SAndroid Build Coastguard Worker #include <cups/file-private.h>
64*5e7646d2SAndroid Build Coastguard Worker #include <cups/sidechannel.h>
65*5e7646d2SAndroid Build Coastguard Worker #include <cups/language-private.h>
66*5e7646d2SAndroid Build Coastguard Worker #include <cups/ppd-private.h>
67*5e7646d2SAndroid Build Coastguard Worker #include "backend-private.h"
68*5e7646d2SAndroid Build Coastguard Worker #include <CoreFoundation/CoreFoundation.h>
69*5e7646d2SAndroid Build Coastguard Worker #include <IOKit/usb/IOUSBLib.h>
70*5e7646d2SAndroid Build Coastguard Worker #include <IOKit/IOCFPlugIn.h>
71*5e7646d2SAndroid Build Coastguard Worker #include <libproc.h>
72*5e7646d2SAndroid Build Coastguard Worker #include <asl.h>
73*5e7646d2SAndroid Build Coastguard Worker #include <spawn.h>
74*5e7646d2SAndroid Build Coastguard Worker #include <pthread.h>
75*5e7646d2SAndroid Build Coastguard Worker 
76*5e7646d2SAndroid Build Coastguard Worker /*
77*5e7646d2SAndroid Build Coastguard Worker  * Include necessary headers.
78*5e7646d2SAndroid Build Coastguard Worker  */
79*5e7646d2SAndroid Build Coastguard Worker 
80*5e7646d2SAndroid Build Coastguard Worker extern char **environ;
81*5e7646d2SAndroid Build Coastguard Worker 
82*5e7646d2SAndroid Build Coastguard Worker 
83*5e7646d2SAndroid Build Coastguard Worker /*
84*5e7646d2SAndroid Build Coastguard Worker  * DEBUG_WRITES, if defined, causes the backend to write data to the printer in
85*5e7646d2SAndroid Build Coastguard Worker  * 512 byte increments, up to 8192 bytes, to make debugging with a USB bus
86*5e7646d2SAndroid Build Coastguard Worker  * analyzer easier.
87*5e7646d2SAndroid Build Coastguard Worker  */
88*5e7646d2SAndroid Build Coastguard Worker 
89*5e7646d2SAndroid Build Coastguard Worker #define DEBUG_WRITES 0
90*5e7646d2SAndroid Build Coastguard Worker 
91*5e7646d2SAndroid Build Coastguard Worker /*
92*5e7646d2SAndroid Build Coastguard Worker  * WAIT_EOF_DELAY is number of seconds we'll wait for responses from
93*5e7646d2SAndroid Build Coastguard Worker  * the printer after we've finished sending all the data
94*5e7646d2SAndroid Build Coastguard Worker  */
95*5e7646d2SAndroid Build Coastguard Worker #define WAIT_EOF_DELAY			7
96*5e7646d2SAndroid Build Coastguard Worker #define WAIT_SIDE_DELAY			3
97*5e7646d2SAndroid Build Coastguard Worker #define DEFAULT_TIMEOUT			5000L
98*5e7646d2SAndroid Build Coastguard Worker 
99*5e7646d2SAndroid Build Coastguard Worker #define	USB_INTERFACE_KIND		CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID245)
100*5e7646d2SAndroid Build Coastguard Worker #define kUSBLanguageEnglish		0x409
101*5e7646d2SAndroid Build Coastguard Worker 
102*5e7646d2SAndroid Build Coastguard Worker #define PRINTER_POLLING_INTERVAL	5			/* seconds */
103*5e7646d2SAndroid Build Coastguard Worker #define INITIAL_LOG_INTERVAL		PRINTER_POLLING_INTERVAL
104*5e7646d2SAndroid Build Coastguard Worker #define SUBSEQUENT_LOG_INTERVAL		3 * INITIAL_LOG_INTERVAL
105*5e7646d2SAndroid Build Coastguard Worker 
106*5e7646d2SAndroid Build Coastguard Worker #define kUSBPrinterClassTypeID		CFUUIDGetConstantUUIDWithBytes(NULL, 0x06, 0x04, 0x7D, 0x16, 0x53, 0xA2, 0x11, 0xD6, 0x92, 0x06, 0x00, 0x30, 0x65, 0x52, 0x45, 0x92)
107*5e7646d2SAndroid Build Coastguard Worker #define	kUSBPrinterClassInterfaceID	CFUUIDGetConstantUUIDWithBytes(NULL, 0x03, 0x34, 0x6D, 0x74, 0x53, 0xA3, 0x11, 0xD6, 0x9E, 0xA1, 0x76, 0x30, 0x65, 0x52, 0x45, 0x92)
108*5e7646d2SAndroid Build Coastguard Worker 
109*5e7646d2SAndroid Build Coastguard Worker #define kUSBClassDriverProperty		CFSTR("USB Printing Class")
110*5e7646d2SAndroid Build Coastguard Worker 
111*5e7646d2SAndroid Build Coastguard Worker #define kUSBGenericTOPrinterClassDriver	CFSTR("/System/Library/Printers/Libraries/USBGenericPrintingClass.plugin")
112*5e7646d2SAndroid Build Coastguard Worker #define kUSBPrinterClassDeviceNotOpen	-9664	/*kPMInvalidIOMContext*/
113*5e7646d2SAndroid Build Coastguard Worker 
114*5e7646d2SAndroid Build Coastguard Worker #define CRSetCrashLogMessage(m) _crc_make_setter(message, m)
115*5e7646d2SAndroid Build Coastguard Worker #define _crc_make_setter(attr, arg) (gCRAnnotations.attr = (uint64_t)(unsigned long)(arg))
116*5e7646d2SAndroid Build Coastguard Worker #define CRASH_REPORTER_CLIENT_HIDDEN __attribute__((visibility("hidden")))
117*5e7646d2SAndroid Build Coastguard Worker #define CRASHREPORTER_ANNOTATIONS_VERSION 4
118*5e7646d2SAndroid Build Coastguard Worker #define CRASHREPORTER_ANNOTATIONS_SECTION "__crash_info"
119*5e7646d2SAndroid Build Coastguard Worker 
120*5e7646d2SAndroid Build Coastguard Worker struct crashreporter_annotations_t {
121*5e7646d2SAndroid Build Coastguard Worker 	uint64_t version;		// unsigned long
122*5e7646d2SAndroid Build Coastguard Worker 	uint64_t message;		// char *
123*5e7646d2SAndroid Build Coastguard Worker 	uint64_t signature_string;	// char *
124*5e7646d2SAndroid Build Coastguard Worker 	uint64_t backtrace;		// char *
125*5e7646d2SAndroid Build Coastguard Worker 	uint64_t message2;		// char *
126*5e7646d2SAndroid Build Coastguard Worker 	uint64_t thread;		// uint64_t
127*5e7646d2SAndroid Build Coastguard Worker 	uint64_t dialog_mode;		// unsigned int
128*5e7646d2SAndroid Build Coastguard Worker };
129*5e7646d2SAndroid Build Coastguard Worker 
130*5e7646d2SAndroid Build Coastguard Worker CRASH_REPORTER_CLIENT_HIDDEN
131*5e7646d2SAndroid Build Coastguard Worker struct crashreporter_annotations_t gCRAnnotations
132*5e7646d2SAndroid Build Coastguard Worker 	__attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION)))
133*5e7646d2SAndroid Build Coastguard Worker 	= { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0 };
134*5e7646d2SAndroid Build Coastguard Worker 
135*5e7646d2SAndroid Build Coastguard Worker /*
136*5e7646d2SAndroid Build Coastguard Worker  * Section 5.3 USB Printing Class spec
137*5e7646d2SAndroid Build Coastguard Worker  */
138*5e7646d2SAndroid Build Coastguard Worker #define kUSBPrintingSubclass			1
139*5e7646d2SAndroid Build Coastguard Worker #define kUSBPrintingProtocolNoOpen		0
140*5e7646d2SAndroid Build Coastguard Worker #define kUSBPrintingProtocolUnidirectional	1
141*5e7646d2SAndroid Build Coastguard Worker #define kUSBPrintingProtocolBidirectional	2
142*5e7646d2SAndroid Build Coastguard Worker #define kUSBPrintingProtocolIPP			4
143*5e7646d2SAndroid Build Coastguard Worker 
144*5e7646d2SAndroid Build Coastguard Worker typedef IOUSBInterfaceInterface245	**printer_interface_t;
145*5e7646d2SAndroid Build Coastguard Worker 
146*5e7646d2SAndroid Build Coastguard Worker typedef struct iodevice_request_s	/**** Device request ****/
147*5e7646d2SAndroid Build Coastguard Worker {
148*5e7646d2SAndroid Build Coastguard Worker   UInt8		requestType;
149*5e7646d2SAndroid Build Coastguard Worker   UInt8		request;
150*5e7646d2SAndroid Build Coastguard Worker   UInt16	value;
151*5e7646d2SAndroid Build Coastguard Worker   UInt16	index;
152*5e7646d2SAndroid Build Coastguard Worker   UInt16	length;
153*5e7646d2SAndroid Build Coastguard Worker   void		*buffer;
154*5e7646d2SAndroid Build Coastguard Worker } iodevice_request_t;
155*5e7646d2SAndroid Build Coastguard Worker 
156*5e7646d2SAndroid Build Coastguard Worker typedef union				/**** Centronics status byte ****/
157*5e7646d2SAndroid Build Coastguard Worker {
158*5e7646d2SAndroid Build Coastguard Worker   char		b;
159*5e7646d2SAndroid Build Coastguard Worker   struct
160*5e7646d2SAndroid Build Coastguard Worker   {
161*5e7646d2SAndroid Build Coastguard Worker     unsigned	reserved0:2;
162*5e7646d2SAndroid Build Coastguard Worker     unsigned	paperError:1;
163*5e7646d2SAndroid Build Coastguard Worker     unsigned	select:1;
164*5e7646d2SAndroid Build Coastguard Worker     unsigned	notError:1;
165*5e7646d2SAndroid Build Coastguard Worker     unsigned	reserved1:3;
166*5e7646d2SAndroid Build Coastguard Worker   } status;
167*5e7646d2SAndroid Build Coastguard Worker } centronics_status_t;
168*5e7646d2SAndroid Build Coastguard Worker 
169*5e7646d2SAndroid Build Coastguard Worker typedef struct classdriver_s		/**** g.classdriver context ****/
170*5e7646d2SAndroid Build Coastguard Worker {
171*5e7646d2SAndroid Build Coastguard Worker   IUNKNOWN_C_GUTS;
172*5e7646d2SAndroid Build Coastguard Worker   CFPlugInRef		plugin;			/* release plugin */
173*5e7646d2SAndroid Build Coastguard Worker   IUnknownVTbl		**factory;		/* Factory */
174*5e7646d2SAndroid Build Coastguard Worker   void			*vendorReference;	/* vendor class specific usage */
175*5e7646d2SAndroid Build Coastguard Worker   UInt32		location;		/* unique location in bus topology */
176*5e7646d2SAndroid Build Coastguard Worker   UInt8			interfaceNumber;	/* Interface number */
177*5e7646d2SAndroid Build Coastguard Worker   UInt16		vendorID;		/* Vendor id */
178*5e7646d2SAndroid Build Coastguard Worker   UInt16		productID;		/* Product id */
179*5e7646d2SAndroid Build Coastguard Worker   printer_interface_t	interface;		/* identify the device to IOKit */
180*5e7646d2SAndroid Build Coastguard Worker   UInt8			outpipe;		/* mandatory bulkOut pipe */
181*5e7646d2SAndroid Build Coastguard Worker   UInt8			inpipe;			/* optional bulkIn pipe */
182*5e7646d2SAndroid Build Coastguard Worker 
183*5e7646d2SAndroid Build Coastguard Worker   /* general class requests */
184*5e7646d2SAndroid Build Coastguard Worker   kern_return_t (*DeviceRequest)(struct classdriver_s **printer, iodevice_request_t *iorequest, UInt16 timeout);
185*5e7646d2SAndroid Build Coastguard Worker   kern_return_t	(*GetString)(struct classdriver_s **printer, UInt8 whichString, UInt16 language, UInt16 timeout, CFStringRef *result);
186*5e7646d2SAndroid Build Coastguard Worker 
187*5e7646d2SAndroid Build Coastguard Worker   /* standard printer class requests */
188*5e7646d2SAndroid Build Coastguard Worker   kern_return_t	(*SoftReset)(struct classdriver_s **printer, UInt16 timeout);
189*5e7646d2SAndroid Build Coastguard Worker   kern_return_t	(*GetCentronicsStatus)(struct classdriver_s **printer, centronics_status_t *result, UInt16 timeout);
190*5e7646d2SAndroid Build Coastguard Worker   kern_return_t	(*GetDeviceID)(struct classdriver_s **printer, CFStringRef *devid, UInt16 timeout);
191*5e7646d2SAndroid Build Coastguard Worker 
192*5e7646d2SAndroid Build Coastguard Worker   /* standard bulk device requests */
193*5e7646d2SAndroid Build Coastguard Worker   kern_return_t (*ReadPipe)(struct classdriver_s **printer, UInt8 *buffer, UInt32 *count);
194*5e7646d2SAndroid Build Coastguard Worker   kern_return_t (*WritePipe)(struct classdriver_s **printer, UInt8 *buffer, UInt32 *count, Boolean eoj);
195*5e7646d2SAndroid Build Coastguard Worker 
196*5e7646d2SAndroid Build Coastguard Worker   /* interface requests */
197*5e7646d2SAndroid Build Coastguard Worker   kern_return_t (*Open)(struct classdriver_s **printer, UInt32 location, UInt8 protocol);
198*5e7646d2SAndroid Build Coastguard Worker   kern_return_t (*Abort)(struct classdriver_s **printer);
199*5e7646d2SAndroid Build Coastguard Worker   kern_return_t (*Close)(struct classdriver_s **printer);
200*5e7646d2SAndroid Build Coastguard Worker 
201*5e7646d2SAndroid Build Coastguard Worker   /* initialize and terminate */
202*5e7646d2SAndroid Build Coastguard Worker   kern_return_t (*Initialize)(struct classdriver_s **printer, struct classdriver_s **baseclass);
203*5e7646d2SAndroid Build Coastguard Worker   kern_return_t (*Terminate)(struct classdriver_s **printer);
204*5e7646d2SAndroid Build Coastguard Worker 
205*5e7646d2SAndroid Build Coastguard Worker } classdriver_t;
206*5e7646d2SAndroid Build Coastguard Worker 
207*5e7646d2SAndroid Build Coastguard Worker typedef Boolean (*iterator_callback_t)(io_service_t obj, printer_interface_t printerIntf, void *refcon);
208*5e7646d2SAndroid Build Coastguard Worker 
209*5e7646d2SAndroid Build Coastguard Worker typedef struct iterator_reference_s	/**** Iterator reference data */
210*5e7646d2SAndroid Build Coastguard Worker {
211*5e7646d2SAndroid Build Coastguard Worker   iterator_callback_t callback;
212*5e7646d2SAndroid Build Coastguard Worker   void		*userdata;
213*5e7646d2SAndroid Build Coastguard Worker   Boolean	keepRunning;
214*5e7646d2SAndroid Build Coastguard Worker } iterator_reference_t;
215*5e7646d2SAndroid Build Coastguard Worker 
216*5e7646d2SAndroid Build Coastguard Worker typedef struct globals_s
217*5e7646d2SAndroid Build Coastguard Worker {
218*5e7646d2SAndroid Build Coastguard Worker   io_service_t		printer_obj;
219*5e7646d2SAndroid Build Coastguard Worker   classdriver_t		**classdriver;
220*5e7646d2SAndroid Build Coastguard Worker 
221*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_t	read_thread_mutex;
222*5e7646d2SAndroid Build Coastguard Worker   pthread_cond_t	read_thread_cond;
223*5e7646d2SAndroid Build Coastguard Worker   int			read_thread_stop;
224*5e7646d2SAndroid Build Coastguard Worker   int			read_thread_done;
225*5e7646d2SAndroid Build Coastguard Worker 
226*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_t	readwrite_lock_mutex;
227*5e7646d2SAndroid Build Coastguard Worker   pthread_cond_t	readwrite_lock_cond;
228*5e7646d2SAndroid Build Coastguard Worker   int			readwrite_lock;
229*5e7646d2SAndroid Build Coastguard Worker 
230*5e7646d2SAndroid Build Coastguard Worker   CFStringRef		make;
231*5e7646d2SAndroid Build Coastguard Worker   CFStringRef		model;
232*5e7646d2SAndroid Build Coastguard Worker   CFStringRef		serial;
233*5e7646d2SAndroid Build Coastguard Worker   UInt32		location;
234*5e7646d2SAndroid Build Coastguard Worker   UInt8			interfaceNum;
235*5e7646d2SAndroid Build Coastguard Worker   UInt8			alternateSetting;
236*5e7646d2SAndroid Build Coastguard Worker   UInt8                 interfaceProtocol;
237*5e7646d2SAndroid Build Coastguard Worker 
238*5e7646d2SAndroid Build Coastguard Worker   CFRunLoopTimerRef 	status_timer;
239*5e7646d2SAndroid Build Coastguard Worker 
240*5e7646d2SAndroid Build Coastguard Worker   int			print_fd;	/* File descriptor to print */
241*5e7646d2SAndroid Build Coastguard Worker   ssize_t		print_bytes;	/* Print bytes read */
242*5e7646d2SAndroid Build Coastguard Worker #if DEBUG_WRITES
243*5e7646d2SAndroid Build Coastguard Worker   ssize_t		debug_bytes;	/* Current bytes to read */
244*5e7646d2SAndroid Build Coastguard Worker #endif /* DEBUG_WRITES */
245*5e7646d2SAndroid Build Coastguard Worker 
246*5e7646d2SAndroid Build Coastguard Worker   Boolean		use_generic_class_driver;
247*5e7646d2SAndroid Build Coastguard Worker   Boolean		wait_eof;
248*5e7646d2SAndroid Build Coastguard Worker   int			drain_output;	/* Drain all pending output */
249*5e7646d2SAndroid Build Coastguard Worker   int			bidi_flag;	/* 0=unidirectional, 1=bidirectional */
250*5e7646d2SAndroid Build Coastguard Worker 
251*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_t	sidechannel_thread_mutex;
252*5e7646d2SAndroid Build Coastguard Worker   pthread_cond_t	sidechannel_thread_cond;
253*5e7646d2SAndroid Build Coastguard Worker   int			sidechannel_thread_stop;
254*5e7646d2SAndroid Build Coastguard Worker   int			sidechannel_thread_done;
255*5e7646d2SAndroid Build Coastguard Worker } globals_t;
256*5e7646d2SAndroid Build Coastguard Worker 
257*5e7646d2SAndroid Build Coastguard Worker 
258*5e7646d2SAndroid Build Coastguard Worker /*
259*5e7646d2SAndroid Build Coastguard Worker  * Globals...
260*5e7646d2SAndroid Build Coastguard Worker  */
261*5e7646d2SAndroid Build Coastguard Worker 
262*5e7646d2SAndroid Build Coastguard Worker globals_t g = { 0 };			/* Globals */
263*5e7646d2SAndroid Build Coastguard Worker int Iterating = 0;			/* Are we iterating the bus? */
264*5e7646d2SAndroid Build Coastguard Worker 
265*5e7646d2SAndroid Build Coastguard Worker 
266*5e7646d2SAndroid Build Coastguard Worker /*
267*5e7646d2SAndroid Build Coastguard Worker  * Local functions...
268*5e7646d2SAndroid Build Coastguard Worker  */
269*5e7646d2SAndroid Build Coastguard Worker 
270*5e7646d2SAndroid Build Coastguard Worker static Boolean list_device_cb(io_service_t obj, printer_interface_t printerIntf, void *refcon);
271*5e7646d2SAndroid Build Coastguard Worker static Boolean find_device_cb(io_service_t obj, printer_interface_t printerIntf, void *refcon);
272*5e7646d2SAndroid Build Coastguard Worker 
273*5e7646d2SAndroid Build Coastguard Worker static CFStringRef cfstr_create_trim(const char *cstr);
274*5e7646d2SAndroid Build Coastguard Worker static CFStringRef copy_value_for_key(CFStringRef deviceID, CFStringRef *keys);
275*5e7646d2SAndroid Build Coastguard Worker static kern_return_t load_classdriver(CFStringRef driverPath, printer_interface_t interface, classdriver_t ***printerDriver);
276*5e7646d2SAndroid Build Coastguard Worker static kern_return_t load_printerdriver(CFStringRef *driverBundlePath);
277*5e7646d2SAndroid Build Coastguard Worker static kern_return_t registry_close(void);
278*5e7646d2SAndroid Build Coastguard Worker static kern_return_t registry_open(CFStringRef *driverBundlePath);
279*5e7646d2SAndroid Build Coastguard Worker static kern_return_t unload_classdriver(classdriver_t ***classdriver);
280*5e7646d2SAndroid Build Coastguard Worker 
281*5e7646d2SAndroid Build Coastguard Worker static void *read_thread(void *reference);
282*5e7646d2SAndroid Build Coastguard Worker static void *sidechannel_thread(void *reference);
283*5e7646d2SAndroid Build Coastguard Worker static void device_added(void *userdata, io_iterator_t iterator);
284*5e7646d2SAndroid Build Coastguard Worker static void get_device_id(cups_sc_status_t *status, char *data, int *datalen);
285*5e7646d2SAndroid Build Coastguard Worker static void iterate_printers(iterator_callback_t callBack, void *userdata);
286*5e7646d2SAndroid Build Coastguard Worker static void parse_options(char *options, char *serial, int serial_size, UInt32 *location, Boolean *wait_eof);
287*5e7646d2SAndroid Build Coastguard Worker static void setup_cfLanguage(void);
288*5e7646d2SAndroid Build Coastguard Worker static void soft_reset(void);
289*5e7646d2SAndroid Build Coastguard Worker static void status_timer_cb(CFRunLoopTimerRef timer, void *info);
290*5e7646d2SAndroid Build Coastguard Worker #define IS_64BIT 1
291*5e7646d2SAndroid Build Coastguard Worker #define IS_NOT_64BIT 0
292*5e7646d2SAndroid Build Coastguard Worker 
293*5e7646d2SAndroid Build Coastguard Worker #if defined(__arm64e__)
294*5e7646d2SAndroid Build Coastguard Worker static pid_t	child_pid;		/* Child PID */
295*5e7646d2SAndroid Build Coastguard Worker static void run_legacy_backend(int argc, char *argv[], int fd) _CUPS_NORETURN;	/* Starts child backend process running as a x86_64 executable */
296*5e7646d2SAndroid Build Coastguard Worker static void sigterm_handler(int sig);    /* SIGTERM handler */
297*5e7646d2SAndroid Build Coastguard Worker #endif /* __arm64e__ */
298*5e7646d2SAndroid Build Coastguard Worker static void sigquit_handler(int sig, siginfo_t *si, void *unused) _CUPS_NORETURN;
299*5e7646d2SAndroid Build Coastguard Worker 
300*5e7646d2SAndroid Build Coastguard Worker #ifdef PARSE_PS_ERRORS
301*5e7646d2SAndroid Build Coastguard Worker static const char *next_line (const char *buffer);
302*5e7646d2SAndroid Build Coastguard Worker static void parse_pserror (char *sockBuffer, int len);
303*5e7646d2SAndroid Build Coastguard Worker #endif /* PARSE_PS_ERRORS */
304*5e7646d2SAndroid Build Coastguard Worker 
305*5e7646d2SAndroid Build Coastguard Worker static printer_interface_t usb_printer_interface_interface(io_service_t usbClass);
306*5e7646d2SAndroid Build Coastguard Worker 
307*5e7646d2SAndroid Build Coastguard Worker static CFStringRef copy_printer_interface_deviceid(printer_interface_t printer, UInt8 alternateSetting);
308*5e7646d2SAndroid Build Coastguard Worker static CFStringRef copy_printer_interface_indexed_description(printer_interface_t  printer, UInt8 index, UInt16 language);
309*5e7646d2SAndroid Build Coastguard Worker static CFStringRef deviceIDCopyManufacturer(CFStringRef deviceID);
310*5e7646d2SAndroid Build Coastguard Worker static CFStringRef deviceIDCopyModel(CFStringRef deviceID);
311*5e7646d2SAndroid Build Coastguard Worker static CFStringRef deviceIDCopySerialNumber(CFStringRef deviceID);
312*5e7646d2SAndroid Build Coastguard Worker 
313*5e7646d2SAndroid Build Coastguard Worker #pragma mark -
314*5e7646d2SAndroid Build Coastguard Worker 
315*5e7646d2SAndroid Build Coastguard Worker /*
316*5e7646d2SAndroid Build Coastguard Worker  * 'list_devices()' - List all USB devices.
317*5e7646d2SAndroid Build Coastguard Worker  */
318*5e7646d2SAndroid Build Coastguard Worker 
list_devices()319*5e7646d2SAndroid Build Coastguard Worker void list_devices()
320*5e7646d2SAndroid Build Coastguard Worker {
321*5e7646d2SAndroid Build Coastguard Worker   iterate_printers(list_device_cb, NULL);
322*5e7646d2SAndroid Build Coastguard Worker }
323*5e7646d2SAndroid Build Coastguard Worker 
324*5e7646d2SAndroid Build Coastguard Worker 
325*5e7646d2SAndroid Build Coastguard Worker /*
326*5e7646d2SAndroid Build Coastguard Worker  * 'print_device()' - Print a file to a USB device.
327*5e7646d2SAndroid Build Coastguard Worker  */
328*5e7646d2SAndroid Build Coastguard Worker 
329*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[])330*5e7646d2SAndroid Build Coastguard Worker print_device(const char *uri,		/* I - Device URI */
331*5e7646d2SAndroid Build Coastguard Worker              const char *hostname,	/* I - Hostname/manufacturer */
332*5e7646d2SAndroid Build Coastguard Worker              const char *resource,	/* I - Resource/modelname */
333*5e7646d2SAndroid Build Coastguard Worker 	     char       *options,	/* I - Device options/serial number */
334*5e7646d2SAndroid Build Coastguard Worker 	     int        print_fd,	/* I - File descriptor to print */
335*5e7646d2SAndroid Build Coastguard Worker 	     int        copies,		/* I - Copies to print */
336*5e7646d2SAndroid Build Coastguard Worker 	     int	argc,		/* I - Number of command-line arguments (6 or 7) */
337*5e7646d2SAndroid Build Coastguard Worker 	     char	*argv[])	/* I - Command-line arguments */
338*5e7646d2SAndroid Build Coastguard Worker {
339*5e7646d2SAndroid Build Coastguard Worker   char		  serial[1024];		/* Serial number buffer */
340*5e7646d2SAndroid Build Coastguard Worker   OSStatus	  status;		/* Function results */
341*5e7646d2SAndroid Build Coastguard Worker   IOReturn	  iostatus;		/* Current IO status */
342*5e7646d2SAndroid Build Coastguard Worker   pthread_t	  read_thread_id,	/* Read thread */
343*5e7646d2SAndroid Build Coastguard Worker 		  sidechannel_thread_id;/* Side-channel thread */
344*5e7646d2SAndroid Build Coastguard Worker   int		  have_sidechannel = 0;	/* Was the side-channel thread started? */
345*5e7646d2SAndroid Build Coastguard Worker   struct stat     sidechannel_info;	/* Side-channel file descriptor info */
346*5e7646d2SAndroid Build Coastguard Worker   char		  print_buffer[8192],	/* Print data buffer */
347*5e7646d2SAndroid Build Coastguard Worker 		  *print_ptr;		/* Pointer into print data buffer */
348*5e7646d2SAndroid Build Coastguard Worker   UInt32	  location;		/* Unique location in bus topology */
349*5e7646d2SAndroid Build Coastguard Worker   fd_set	  input_set;		/* Input set for select() */
350*5e7646d2SAndroid Build Coastguard Worker   CFStringRef	  driverBundlePath;	/* Class driver path */
351*5e7646d2SAndroid Build Coastguard Worker   int		  countdown,		/* Logging interval */
352*5e7646d2SAndroid Build Coastguard Worker 		  nfds;			/* Number of file descriptors */
353*5e7646d2SAndroid Build Coastguard Worker   ssize_t	  total_bytes;		/* Total bytes written */
354*5e7646d2SAndroid Build Coastguard Worker   UInt32	  bytes;		/* Bytes written */
355*5e7646d2SAndroid Build Coastguard Worker   struct timeval  *timeout,		/* Timeout pointer */
356*5e7646d2SAndroid Build Coastguard Worker 		  tv;			/* Time value */
357*5e7646d2SAndroid Build Coastguard Worker   struct timespec cond_timeout;		/* pthread condition timeout */
358*5e7646d2SAndroid Build Coastguard Worker   struct sigaction action;		/* Actions for POSIX signals */
359*5e7646d2SAndroid Build Coastguard Worker 
360*5e7646d2SAndroid Build Coastguard Worker 
361*5e7646d2SAndroid Build Coastguard Worker   (void)uri;
362*5e7646d2SAndroid Build Coastguard Worker   (void)argc;
363*5e7646d2SAndroid Build Coastguard Worker   (void)argv;
364*5e7646d2SAndroid Build Coastguard Worker 
365*5e7646d2SAndroid Build Coastguard Worker  /*
366*5e7646d2SAndroid Build Coastguard Worker   * Catch SIGQUIT to determine who is sending it...
367*5e7646d2SAndroid Build Coastguard Worker   */
368*5e7646d2SAndroid Build Coastguard Worker 
369*5e7646d2SAndroid Build Coastguard Worker   memset(&action, 0, sizeof(action));
370*5e7646d2SAndroid Build Coastguard Worker   action.sa_sigaction = sigquit_handler;
371*5e7646d2SAndroid Build Coastguard Worker   action.sa_flags = SA_SIGINFO;
372*5e7646d2SAndroid Build Coastguard Worker   sigaction(SIGQUIT, &action, NULL);
373*5e7646d2SAndroid Build Coastguard Worker 
374*5e7646d2SAndroid Build Coastguard Worker  /*
375*5e7646d2SAndroid Build Coastguard Worker   * See if the side-channel descriptor is valid...
376*5e7646d2SAndroid Build Coastguard Worker   */
377*5e7646d2SAndroid Build Coastguard Worker 
378*5e7646d2SAndroid Build Coastguard Worker   have_sidechannel = !fstat(CUPS_SC_FD, &sidechannel_info) &&
379*5e7646d2SAndroid Build Coastguard Worker                      S_ISSOCK(sidechannel_info.st_mode);
380*5e7646d2SAndroid Build Coastguard Worker 
381*5e7646d2SAndroid Build Coastguard Worker  /*
382*5e7646d2SAndroid Build Coastguard Worker   * Localize using CoreFoundation...
383*5e7646d2SAndroid Build Coastguard Worker   */
384*5e7646d2SAndroid Build Coastguard Worker 
385*5e7646d2SAndroid Build Coastguard Worker   setup_cfLanguage();
386*5e7646d2SAndroid Build Coastguard Worker 
387*5e7646d2SAndroid Build Coastguard Worker   parse_options(options, serial, sizeof(serial), &location, &g.wait_eof);
388*5e7646d2SAndroid Build Coastguard Worker 
389*5e7646d2SAndroid Build Coastguard Worker   if (resource[0] == '/')
390*5e7646d2SAndroid Build Coastguard Worker     resource++;
391*5e7646d2SAndroid Build Coastguard Worker 
392*5e7646d2SAndroid Build Coastguard Worker   g.print_fd	= print_fd;
393*5e7646d2SAndroid Build Coastguard Worker   g.make	= cfstr_create_trim(hostname);
394*5e7646d2SAndroid Build Coastguard Worker   g.model	= cfstr_create_trim(resource);
395*5e7646d2SAndroid Build Coastguard Worker   g.serial	= cfstr_create_trim(serial);
396*5e7646d2SAndroid Build Coastguard Worker   g.location	= location;
397*5e7646d2SAndroid Build Coastguard Worker 
398*5e7646d2SAndroid Build Coastguard Worker   if (!g.make || !g.model)
399*5e7646d2SAndroid Build Coastguard Worker   {
400*5e7646d2SAndroid Build Coastguard Worker     fprintf(stderr, "DEBUG: Fatal USB error.\n");
401*5e7646d2SAndroid Build Coastguard Worker     _cupsLangPrintFilter(stderr, "ERROR",
402*5e7646d2SAndroid Build Coastguard Worker                          _("There was an unrecoverable USB error."));
403*5e7646d2SAndroid Build Coastguard Worker 
404*5e7646d2SAndroid Build Coastguard Worker     if (!g.make)
405*5e7646d2SAndroid Build Coastguard Worker       fputs("DEBUG: USB make string is NULL\n", stderr);
406*5e7646d2SAndroid Build Coastguard Worker     if (!g.model)
407*5e7646d2SAndroid Build Coastguard Worker       fputs("DEBUG: USB model string is NULL\n", stderr);
408*5e7646d2SAndroid Build Coastguard Worker 
409*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_BACKEND_STOP);
410*5e7646d2SAndroid Build Coastguard Worker   }
411*5e7646d2SAndroid Build Coastguard Worker 
412*5e7646d2SAndroid Build Coastguard Worker   fputs("STATE: +connecting-to-device\n", stderr);
413*5e7646d2SAndroid Build Coastguard Worker 
414*5e7646d2SAndroid Build Coastguard Worker   countdown = INITIAL_LOG_INTERVAL;
415*5e7646d2SAndroid Build Coastguard Worker 
416*5e7646d2SAndroid Build Coastguard Worker   do
417*5e7646d2SAndroid Build Coastguard Worker   {
418*5e7646d2SAndroid Build Coastguard Worker     if (g.printer_obj)
419*5e7646d2SAndroid Build Coastguard Worker     {
420*5e7646d2SAndroid Build Coastguard Worker       IOObjectRelease(g.printer_obj);
421*5e7646d2SAndroid Build Coastguard Worker       unload_classdriver(&g.classdriver);
422*5e7646d2SAndroid Build Coastguard Worker       g.printer_obj = 0x0;
423*5e7646d2SAndroid Build Coastguard Worker       g.classdriver = 0x0;
424*5e7646d2SAndroid Build Coastguard Worker     }
425*5e7646d2SAndroid Build Coastguard Worker     fprintf(stderr, "DEBUG: Looking for '%s %s'\n", hostname, resource);
426*5e7646d2SAndroid Build Coastguard Worker 
427*5e7646d2SAndroid Build Coastguard Worker     do
428*5e7646d2SAndroid Build Coastguard Worker     {
429*5e7646d2SAndroid Build Coastguard Worker       iterate_printers(find_device_cb, NULL);
430*5e7646d2SAndroid Build Coastguard Worker       if (g.printer_obj != 0x0)
431*5e7646d2SAndroid Build Coastguard Worker         break;
432*5e7646d2SAndroid Build Coastguard Worker 
433*5e7646d2SAndroid Build Coastguard Worker       _cupsLangPrintFilter(stderr, "INFO", _("Waiting for printer to become available."));
434*5e7646d2SAndroid Build Coastguard Worker       sleep(5);
435*5e7646d2SAndroid Build Coastguard Worker     } while (true);
436*5e7646d2SAndroid Build Coastguard Worker 
437*5e7646d2SAndroid Build Coastguard Worker     fputs("DEBUG: Opening connection\n", stderr);
438*5e7646d2SAndroid Build Coastguard Worker 
439*5e7646d2SAndroid Build Coastguard Worker     driverBundlePath = NULL;
440*5e7646d2SAndroid Build Coastguard Worker 
441*5e7646d2SAndroid Build Coastguard Worker     status = registry_open(&driverBundlePath);
442*5e7646d2SAndroid Build Coastguard Worker 
443*5e7646d2SAndroid Build Coastguard Worker #if defined(__arm64e__)
444*5e7646d2SAndroid Build Coastguard Worker     /*
445*5e7646d2SAndroid Build Coastguard Worker      * If we were unable to load the class drivers for this printer it's
446*5e7646d2SAndroid Build Coastguard Worker      * probably because they're x86_64 (or older). In this case try to run this
447*5e7646d2SAndroid Build Coastguard Worker      * backend as x86_64 so we can use them...
448*5e7646d2SAndroid Build Coastguard Worker      */
449*5e7646d2SAndroid Build Coastguard Worker     if (status == -2)
450*5e7646d2SAndroid Build Coastguard Worker     {
451*5e7646d2SAndroid Build Coastguard Worker       run_legacy_backend(argc, argv, print_fd);
452*5e7646d2SAndroid Build Coastguard Worker       /* Never returns here */
453*5e7646d2SAndroid Build Coastguard Worker     }
454*5e7646d2SAndroid Build Coastguard Worker #endif /* __arm64e__ */
455*5e7646d2SAndroid Build Coastguard Worker 
456*5e7646d2SAndroid Build Coastguard Worker     if (status ==  -2)
457*5e7646d2SAndroid Build Coastguard Worker     {
458*5e7646d2SAndroid Build Coastguard Worker      /*
459*5e7646d2SAndroid Build Coastguard Worker       * If we still were unable to load the class drivers for this printer log
460*5e7646d2SAndroid Build Coastguard Worker       * the error and stop the queue...
461*5e7646d2SAndroid Build Coastguard Worker       */
462*5e7646d2SAndroid Build Coastguard Worker 
463*5e7646d2SAndroid Build Coastguard Worker       if (driverBundlePath == NULL || !CFStringGetCString(driverBundlePath, print_buffer, sizeof(print_buffer), kCFStringEncodingUTF8))
464*5e7646d2SAndroid Build Coastguard Worker         strlcpy(print_buffer, "USB class driver", sizeof(print_buffer));
465*5e7646d2SAndroid Build Coastguard Worker 
466*5e7646d2SAndroid Build Coastguard Worker       fputs("STATE: +apple-missing-usbclassdriver-error\n", stderr);
467*5e7646d2SAndroid Build Coastguard Worker       _cupsLangPrintFilter(stderr, "ERROR",
468*5e7646d2SAndroid Build Coastguard Worker 			   _("There was an unrecoverable USB error."));
469*5e7646d2SAndroid Build Coastguard Worker       fprintf(stderr, "DEBUG: Could not load %s\n", print_buffer);
470*5e7646d2SAndroid Build Coastguard Worker 
471*5e7646d2SAndroid Build Coastguard Worker       if (driverBundlePath)
472*5e7646d2SAndroid Build Coastguard Worker 	CFRelease(driverBundlePath);
473*5e7646d2SAndroid Build Coastguard Worker 
474*5e7646d2SAndroid Build Coastguard Worker       return (CUPS_BACKEND_STOP);
475*5e7646d2SAndroid Build Coastguard Worker     }
476*5e7646d2SAndroid Build Coastguard Worker 
477*5e7646d2SAndroid Build Coastguard Worker     if (driverBundlePath)
478*5e7646d2SAndroid Build Coastguard Worker       CFRelease(driverBundlePath);
479*5e7646d2SAndroid Build Coastguard Worker 
480*5e7646d2SAndroid Build Coastguard Worker     if (status != noErr)
481*5e7646d2SAndroid Build Coastguard Worker     {
482*5e7646d2SAndroid Build Coastguard Worker       sleep(PRINTER_POLLING_INTERVAL);
483*5e7646d2SAndroid Build Coastguard Worker       countdown -= PRINTER_POLLING_INTERVAL;
484*5e7646d2SAndroid Build Coastguard Worker       if (countdown <= 0)
485*5e7646d2SAndroid Build Coastguard Worker       {
486*5e7646d2SAndroid Build Coastguard Worker 	_cupsLangPrintFilter(stderr, "INFO",
487*5e7646d2SAndroid Build Coastguard Worker 		             _("Waiting for printer to become available."));
488*5e7646d2SAndroid Build Coastguard Worker 	fprintf(stderr, "DEBUG: USB printer status: 0x%08x\n", (int)status);
489*5e7646d2SAndroid Build Coastguard Worker 	countdown = SUBSEQUENT_LOG_INTERVAL;	/* subsequent log entries, every 15 seconds */
490*5e7646d2SAndroid Build Coastguard Worker       }
491*5e7646d2SAndroid Build Coastguard Worker     }
492*5e7646d2SAndroid Build Coastguard Worker   } while (status != noErr);
493*5e7646d2SAndroid Build Coastguard Worker 
494*5e7646d2SAndroid Build Coastguard Worker   fputs("STATE: -connecting-to-device\n", stderr);
495*5e7646d2SAndroid Build Coastguard Worker 
496*5e7646d2SAndroid Build Coastguard Worker   /*
497*5e7646d2SAndroid Build Coastguard Worker    * Now that we are "connected" to the port, ignore SIGTERM so that we
498*5e7646d2SAndroid Build Coastguard Worker    * can finish out any page data the driver sends (e.g. to eject the
499*5e7646d2SAndroid Build Coastguard Worker    * current page...  Only ignore SIGTERM if we are printing data from
500*5e7646d2SAndroid Build Coastguard Worker    * stdin (otherwise you can't cancel raw jobs...)
501*5e7646d2SAndroid Build Coastguard Worker    */
502*5e7646d2SAndroid Build Coastguard Worker 
503*5e7646d2SAndroid Build Coastguard Worker   if (!print_fd)
504*5e7646d2SAndroid Build Coastguard Worker   {
505*5e7646d2SAndroid Build Coastguard Worker     memset(&action, 0, sizeof(action));
506*5e7646d2SAndroid Build Coastguard Worker 
507*5e7646d2SAndroid Build Coastguard Worker     sigemptyset(&action.sa_mask);
508*5e7646d2SAndroid Build Coastguard Worker     action.sa_handler = SIG_IGN;
509*5e7646d2SAndroid Build Coastguard Worker     sigaction(SIGTERM, &action, NULL);
510*5e7646d2SAndroid Build Coastguard Worker   }
511*5e7646d2SAndroid Build Coastguard Worker 
512*5e7646d2SAndroid Build Coastguard Worker  /*
513*5e7646d2SAndroid Build Coastguard Worker   * Start the side channel thread if the descriptor is valid...
514*5e7646d2SAndroid Build Coastguard Worker   */
515*5e7646d2SAndroid Build Coastguard Worker 
516*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_init(&g.readwrite_lock_mutex, NULL);
517*5e7646d2SAndroid Build Coastguard Worker   pthread_cond_init(&g.readwrite_lock_cond, NULL);
518*5e7646d2SAndroid Build Coastguard Worker   g.readwrite_lock = 1;
519*5e7646d2SAndroid Build Coastguard Worker 
520*5e7646d2SAndroid Build Coastguard Worker   if (have_sidechannel)
521*5e7646d2SAndroid Build Coastguard Worker   {
522*5e7646d2SAndroid Build Coastguard Worker     g.sidechannel_thread_stop = 0;
523*5e7646d2SAndroid Build Coastguard Worker     g.sidechannel_thread_done = 0;
524*5e7646d2SAndroid Build Coastguard Worker 
525*5e7646d2SAndroid Build Coastguard Worker     pthread_cond_init(&g.sidechannel_thread_cond, NULL);
526*5e7646d2SAndroid Build Coastguard Worker     pthread_mutex_init(&g.sidechannel_thread_mutex, NULL);
527*5e7646d2SAndroid Build Coastguard Worker 
528*5e7646d2SAndroid Build Coastguard Worker     if (pthread_create(&sidechannel_thread_id, NULL, sidechannel_thread, NULL))
529*5e7646d2SAndroid Build Coastguard Worker     {
530*5e7646d2SAndroid Build Coastguard Worker       fprintf(stderr, "DEBUG: Fatal USB error.\n");
531*5e7646d2SAndroid Build Coastguard Worker       _cupsLangPrintFilter(stderr, "ERROR",
532*5e7646d2SAndroid Build Coastguard Worker 			   _("There was an unrecoverable USB error."));
533*5e7646d2SAndroid Build Coastguard Worker       fputs("DEBUG: Couldn't create side-channel thread\n", stderr);
534*5e7646d2SAndroid Build Coastguard Worker       registry_close();
535*5e7646d2SAndroid Build Coastguard Worker       return (CUPS_BACKEND_STOP);
536*5e7646d2SAndroid Build Coastguard Worker     }
537*5e7646d2SAndroid Build Coastguard Worker   }
538*5e7646d2SAndroid Build Coastguard Worker 
539*5e7646d2SAndroid Build Coastguard Worker  /*
540*5e7646d2SAndroid Build Coastguard Worker   * Get the read thread going...
541*5e7646d2SAndroid Build Coastguard Worker   */
542*5e7646d2SAndroid Build Coastguard Worker 
543*5e7646d2SAndroid Build Coastguard Worker   g.read_thread_stop = 0;
544*5e7646d2SAndroid Build Coastguard Worker   g.read_thread_done = 0;
545*5e7646d2SAndroid Build Coastguard Worker 
546*5e7646d2SAndroid Build Coastguard Worker   pthread_cond_init(&g.read_thread_cond, NULL);
547*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_init(&g.read_thread_mutex, NULL);
548*5e7646d2SAndroid Build Coastguard Worker 
549*5e7646d2SAndroid Build Coastguard Worker   if (pthread_create(&read_thread_id, NULL, read_thread, NULL))
550*5e7646d2SAndroid Build Coastguard Worker   {
551*5e7646d2SAndroid Build Coastguard Worker     fprintf(stderr, "DEBUG: Fatal USB error.\n");
552*5e7646d2SAndroid Build Coastguard Worker     _cupsLangPrintFilter(stderr, "ERROR",
553*5e7646d2SAndroid Build Coastguard Worker                          _("There was an unrecoverable USB error."));
554*5e7646d2SAndroid Build Coastguard Worker     fputs("DEBUG: Couldn't create read thread\n", stderr);
555*5e7646d2SAndroid Build Coastguard Worker     registry_close();
556*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_BACKEND_STOP);
557*5e7646d2SAndroid Build Coastguard Worker   }
558*5e7646d2SAndroid Build Coastguard Worker 
559*5e7646d2SAndroid Build Coastguard Worker  /*
560*5e7646d2SAndroid Build Coastguard Worker   * The main thread sends the print file...
561*5e7646d2SAndroid Build Coastguard Worker   */
562*5e7646d2SAndroid Build Coastguard Worker 
563*5e7646d2SAndroid Build Coastguard Worker   g.drain_output = 0;
564*5e7646d2SAndroid Build Coastguard Worker   g.print_bytes	 = 0;
565*5e7646d2SAndroid Build Coastguard Worker   total_bytes	 = 0;
566*5e7646d2SAndroid Build Coastguard Worker   print_ptr	 = print_buffer;
567*5e7646d2SAndroid Build Coastguard Worker 
568*5e7646d2SAndroid Build Coastguard Worker   while (status == noErr && copies-- > 0)
569*5e7646d2SAndroid Build Coastguard Worker   {
570*5e7646d2SAndroid Build Coastguard Worker     _cupsLangPrintFilter(stderr, "INFO", _("Sending data to printer."));
571*5e7646d2SAndroid Build Coastguard Worker 
572*5e7646d2SAndroid Build Coastguard Worker     if (print_fd != STDIN_FILENO)
573*5e7646d2SAndroid Build Coastguard Worker     {
574*5e7646d2SAndroid Build Coastguard Worker       fputs("PAGE: 1 1\n", stderr);
575*5e7646d2SAndroid Build Coastguard Worker       lseek(print_fd, 0, SEEK_SET);
576*5e7646d2SAndroid Build Coastguard Worker     }
577*5e7646d2SAndroid Build Coastguard Worker 
578*5e7646d2SAndroid Build Coastguard Worker     while (status == noErr)
579*5e7646d2SAndroid Build Coastguard Worker     {
580*5e7646d2SAndroid Build Coastguard Worker       FD_ZERO(&input_set);
581*5e7646d2SAndroid Build Coastguard Worker 
582*5e7646d2SAndroid Build Coastguard Worker       if (!g.print_bytes)
583*5e7646d2SAndroid Build Coastguard Worker 	FD_SET(print_fd, &input_set);
584*5e7646d2SAndroid Build Coastguard Worker 
585*5e7646d2SAndroid Build Coastguard Worker      /*
586*5e7646d2SAndroid Build Coastguard Worker       * Calculate select timeout...
587*5e7646d2SAndroid Build Coastguard Worker       *   If we have data waiting to send timeout is 100ms.
588*5e7646d2SAndroid Build Coastguard Worker       *   else if we're draining print_fd timeout is 0.
589*5e7646d2SAndroid Build Coastguard Worker       *   else we're waiting forever...
590*5e7646d2SAndroid Build Coastguard Worker       */
591*5e7646d2SAndroid Build Coastguard Worker 
592*5e7646d2SAndroid Build Coastguard Worker       if (g.print_bytes)
593*5e7646d2SAndroid Build Coastguard Worker       {
594*5e7646d2SAndroid Build Coastguard Worker 	tv.tv_sec  = 0;
595*5e7646d2SAndroid Build Coastguard Worker 	tv.tv_usec = 100000;		/* 100ms */
596*5e7646d2SAndroid Build Coastguard Worker 	timeout = &tv;
597*5e7646d2SAndroid Build Coastguard Worker       }
598*5e7646d2SAndroid Build Coastguard Worker       else if (g.drain_output)
599*5e7646d2SAndroid Build Coastguard Worker       {
600*5e7646d2SAndroid Build Coastguard Worker 	tv.tv_sec  = 0;
601*5e7646d2SAndroid Build Coastguard Worker 	tv.tv_usec = 0;
602*5e7646d2SAndroid Build Coastguard Worker 	timeout = &tv;
603*5e7646d2SAndroid Build Coastguard Worker       }
604*5e7646d2SAndroid Build Coastguard Worker       else
605*5e7646d2SAndroid Build Coastguard Worker 	timeout = NULL;
606*5e7646d2SAndroid Build Coastguard Worker 
607*5e7646d2SAndroid Build Coastguard Worker      /*
608*5e7646d2SAndroid Build Coastguard Worker       * I/O is unlocked around select...
609*5e7646d2SAndroid Build Coastguard Worker       */
610*5e7646d2SAndroid Build Coastguard Worker 
611*5e7646d2SAndroid Build Coastguard Worker       pthread_mutex_lock(&g.readwrite_lock_mutex);
612*5e7646d2SAndroid Build Coastguard Worker       g.readwrite_lock = 0;
613*5e7646d2SAndroid Build Coastguard Worker       pthread_cond_signal(&g.readwrite_lock_cond);
614*5e7646d2SAndroid Build Coastguard Worker       pthread_mutex_unlock(&g.readwrite_lock_mutex);
615*5e7646d2SAndroid Build Coastguard Worker 
616*5e7646d2SAndroid Build Coastguard Worker       nfds = select(print_fd + 1, &input_set, NULL, NULL, timeout);
617*5e7646d2SAndroid Build Coastguard Worker 
618*5e7646d2SAndroid Build Coastguard Worker      /*
619*5e7646d2SAndroid Build Coastguard Worker       * Reacquire the lock...
620*5e7646d2SAndroid Build Coastguard Worker       */
621*5e7646d2SAndroid Build Coastguard Worker 
622*5e7646d2SAndroid Build Coastguard Worker       pthread_mutex_lock(&g.readwrite_lock_mutex);
623*5e7646d2SAndroid Build Coastguard Worker       while (g.readwrite_lock)
624*5e7646d2SAndroid Build Coastguard Worker 	pthread_cond_wait(&g.readwrite_lock_cond, &g.readwrite_lock_mutex);
625*5e7646d2SAndroid Build Coastguard Worker       g.readwrite_lock = 1;
626*5e7646d2SAndroid Build Coastguard Worker       pthread_mutex_unlock(&g.readwrite_lock_mutex);
627*5e7646d2SAndroid Build Coastguard Worker 
628*5e7646d2SAndroid Build Coastguard Worker       if (nfds < 0)
629*5e7646d2SAndroid Build Coastguard Worker       {
630*5e7646d2SAndroid Build Coastguard Worker 	if (errno == EINTR && total_bytes == 0)
631*5e7646d2SAndroid Build Coastguard Worker 	{
632*5e7646d2SAndroid Build Coastguard Worker 	  fputs("DEBUG: Received an interrupt before any bytes were "
633*5e7646d2SAndroid Build Coastguard Worker 	        "written, aborting\n", stderr);
634*5e7646d2SAndroid Build Coastguard Worker           registry_close();
635*5e7646d2SAndroid Build Coastguard Worker           return (CUPS_BACKEND_OK);
636*5e7646d2SAndroid Build Coastguard Worker 	}
637*5e7646d2SAndroid Build Coastguard Worker 	else if (errno != EAGAIN && errno != EINTR)
638*5e7646d2SAndroid Build Coastguard Worker 	{
639*5e7646d2SAndroid Build Coastguard Worker 	  _cupsLangPrintFilter(stderr, "ERROR",
640*5e7646d2SAndroid Build Coastguard Worker 	                       _("Unable to read print data."));
641*5e7646d2SAndroid Build Coastguard Worker 	  perror("DEBUG: select");
642*5e7646d2SAndroid Build Coastguard Worker 	  registry_close();
643*5e7646d2SAndroid Build Coastguard Worker           return (CUPS_BACKEND_FAILED);
644*5e7646d2SAndroid Build Coastguard Worker 	}
645*5e7646d2SAndroid Build Coastguard Worker       }
646*5e7646d2SAndroid Build Coastguard Worker 
647*5e7646d2SAndroid Build Coastguard Worker      /*
648*5e7646d2SAndroid Build Coastguard Worker       * If drain output has finished send a response...
649*5e7646d2SAndroid Build Coastguard Worker       */
650*5e7646d2SAndroid Build Coastguard Worker 
651*5e7646d2SAndroid Build Coastguard Worker       if (g.drain_output && !nfds && !g.print_bytes)
652*5e7646d2SAndroid Build Coastguard Worker       {
653*5e7646d2SAndroid Build Coastguard Worker 	/* Send a response... */
654*5e7646d2SAndroid Build Coastguard Worker 	cupsSideChannelWrite(CUPS_SC_CMD_DRAIN_OUTPUT, CUPS_SC_STATUS_OK, NULL, 0, 1.0);
655*5e7646d2SAndroid Build Coastguard Worker 	g.drain_output = 0;
656*5e7646d2SAndroid Build Coastguard Worker       }
657*5e7646d2SAndroid Build Coastguard Worker 
658*5e7646d2SAndroid Build Coastguard Worker      /*
659*5e7646d2SAndroid Build Coastguard Worker       * Check if we have print data ready...
660*5e7646d2SAndroid Build Coastguard Worker       */
661*5e7646d2SAndroid Build Coastguard Worker 
662*5e7646d2SAndroid Build Coastguard Worker       if (FD_ISSET(print_fd, &input_set))
663*5e7646d2SAndroid Build Coastguard Worker       {
664*5e7646d2SAndroid Build Coastguard Worker #if DEBUG_WRITES
665*5e7646d2SAndroid Build Coastguard Worker 	g.debug_bytes += 512;
666*5e7646d2SAndroid Build Coastguard Worker         if (g.debug_bytes > sizeof(print_buffer))
667*5e7646d2SAndroid Build Coastguard Worker 	  g.debug_bytes = 512;
668*5e7646d2SAndroid Build Coastguard Worker 
669*5e7646d2SAndroid Build Coastguard Worker 	g.print_bytes = read(print_fd, print_buffer, g.debug_bytes);
670*5e7646d2SAndroid Build Coastguard Worker 
671*5e7646d2SAndroid Build Coastguard Worker #else
672*5e7646d2SAndroid Build Coastguard Worker 	g.print_bytes = read(print_fd, print_buffer, sizeof(print_buffer));
673*5e7646d2SAndroid Build Coastguard Worker #endif /* DEBUG_WRITES */
674*5e7646d2SAndroid Build Coastguard Worker 
675*5e7646d2SAndroid Build Coastguard Worker 	if (g.print_bytes < 0)
676*5e7646d2SAndroid Build Coastguard Worker 	{
677*5e7646d2SAndroid Build Coastguard Worker 	 /*
678*5e7646d2SAndroid Build Coastguard Worker 	  * Read error - bail if we don't see EAGAIN or EINTR...
679*5e7646d2SAndroid Build Coastguard Worker 	  */
680*5e7646d2SAndroid Build Coastguard Worker 
681*5e7646d2SAndroid Build Coastguard Worker 	  if (errno != EAGAIN && errno != EINTR)
682*5e7646d2SAndroid Build Coastguard Worker 	  {
683*5e7646d2SAndroid Build Coastguard Worker 	    _cupsLangPrintFilter(stderr, "ERROR",
684*5e7646d2SAndroid Build Coastguard Worker 				 _("Unable to read print data."));
685*5e7646d2SAndroid Build Coastguard Worker 	    perror("DEBUG: read");
686*5e7646d2SAndroid Build Coastguard Worker 	    registry_close();
687*5e7646d2SAndroid Build Coastguard Worker 	    return (CUPS_BACKEND_FAILED);
688*5e7646d2SAndroid Build Coastguard Worker 	  }
689*5e7646d2SAndroid Build Coastguard Worker 
690*5e7646d2SAndroid Build Coastguard Worker 	  g.print_bytes = 0;
691*5e7646d2SAndroid Build Coastguard Worker 	}
692*5e7646d2SAndroid Build Coastguard Worker 	else if (g.print_bytes == 0)
693*5e7646d2SAndroid Build Coastguard Worker 	{
694*5e7646d2SAndroid Build Coastguard Worker 	 /*
695*5e7646d2SAndroid Build Coastguard Worker 	  * End of file, break out of the loop...
696*5e7646d2SAndroid Build Coastguard Worker 	  */
697*5e7646d2SAndroid Build Coastguard Worker 
698*5e7646d2SAndroid Build Coastguard Worker 	  break;
699*5e7646d2SAndroid Build Coastguard Worker 	}
700*5e7646d2SAndroid Build Coastguard Worker 
701*5e7646d2SAndroid Build Coastguard Worker 	print_ptr = print_buffer;
702*5e7646d2SAndroid Build Coastguard Worker 
703*5e7646d2SAndroid Build Coastguard Worker 	fprintf(stderr, "DEBUG: Read %d bytes of print data...\n",
704*5e7646d2SAndroid Build Coastguard Worker 		(int)g.print_bytes);
705*5e7646d2SAndroid Build Coastguard Worker       }
706*5e7646d2SAndroid Build Coastguard Worker 
707*5e7646d2SAndroid Build Coastguard Worker       if (g.print_bytes)
708*5e7646d2SAndroid Build Coastguard Worker       {
709*5e7646d2SAndroid Build Coastguard Worker 	bytes    = (UInt32)g.print_bytes;
710*5e7646d2SAndroid Build Coastguard Worker 	iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
711*5e7646d2SAndroid Build Coastguard Worker 
712*5e7646d2SAndroid Build Coastguard Worker        /*
713*5e7646d2SAndroid Build Coastguard Worker 	* Ignore timeout errors, but retain the number of bytes written to
714*5e7646d2SAndroid Build Coastguard Worker 	* avoid sending duplicate data...
715*5e7646d2SAndroid Build Coastguard Worker 	*/
716*5e7646d2SAndroid Build Coastguard Worker 
717*5e7646d2SAndroid Build Coastguard Worker 	if (iostatus == kIOUSBTransactionTimeout)
718*5e7646d2SAndroid Build Coastguard Worker 	{
719*5e7646d2SAndroid Build Coastguard Worker 	  fputs("DEBUG: Got USB transaction timeout during write\n", stderr);
720*5e7646d2SAndroid Build Coastguard Worker 	  iostatus = 0;
721*5e7646d2SAndroid Build Coastguard Worker 	}
722*5e7646d2SAndroid Build Coastguard Worker 
723*5e7646d2SAndroid Build Coastguard Worker        /*
724*5e7646d2SAndroid Build Coastguard Worker         * If we've stalled, retry the write...
725*5e7646d2SAndroid Build Coastguard Worker 	*/
726*5e7646d2SAndroid Build Coastguard Worker 
727*5e7646d2SAndroid Build Coastguard Worker 	else if (iostatus == kIOUSBPipeStalled)
728*5e7646d2SAndroid Build Coastguard Worker 	{
729*5e7646d2SAndroid Build Coastguard Worker 	  fputs("DEBUG: Got USB pipe stalled during write\n", stderr);
730*5e7646d2SAndroid Build Coastguard Worker 
731*5e7646d2SAndroid Build Coastguard Worker 	  bytes    = (UInt32)g.print_bytes;
732*5e7646d2SAndroid Build Coastguard Worker 	  iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
733*5e7646d2SAndroid Build Coastguard Worker 	}
734*5e7646d2SAndroid Build Coastguard Worker 
735*5e7646d2SAndroid Build Coastguard Worker        /*
736*5e7646d2SAndroid Build Coastguard Worker 	* Retry a write after an aborted write since we probably just got
737*5e7646d2SAndroid Build Coastguard Worker 	* SIGTERM...
738*5e7646d2SAndroid Build Coastguard Worker 	*/
739*5e7646d2SAndroid Build Coastguard Worker 
740*5e7646d2SAndroid Build Coastguard Worker 	else if (iostatus == kIOReturnAborted)
741*5e7646d2SAndroid Build Coastguard Worker 	{
742*5e7646d2SAndroid Build Coastguard Worker 	  fputs("DEBUG: Got USB return aborted during write\n", stderr);
743*5e7646d2SAndroid Build Coastguard Worker 
744*5e7646d2SAndroid Build Coastguard Worker 	  IOReturn err = (*g.classdriver)->Abort(g.classdriver);
745*5e7646d2SAndroid Build Coastguard Worker 	  fprintf(stderr, "DEBUG: USB class driver Abort returned %x\n", err);
746*5e7646d2SAndroid Build Coastguard Worker 
747*5e7646d2SAndroid Build Coastguard Worker #if DEBUG_WRITES
748*5e7646d2SAndroid Build Coastguard Worker           sleep(5);
749*5e7646d2SAndroid Build Coastguard Worker #endif /* DEBUG_WRITES */
750*5e7646d2SAndroid Build Coastguard Worker 
751*5e7646d2SAndroid Build Coastguard Worker 	  bytes    = (UInt32)g.print_bytes;
752*5e7646d2SAndroid Build Coastguard Worker 	  iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
753*5e7646d2SAndroid Build Coastguard Worker         }
754*5e7646d2SAndroid Build Coastguard Worker 
755*5e7646d2SAndroid Build Coastguard Worker 	if (iostatus)
756*5e7646d2SAndroid Build Coastguard Worker 	{
757*5e7646d2SAndroid Build Coastguard Worker 	 /*
758*5e7646d2SAndroid Build Coastguard Worker 	  * Write error - bail if we don't see an error we can retry...
759*5e7646d2SAndroid Build Coastguard Worker 	  */
760*5e7646d2SAndroid Build Coastguard Worker 
761*5e7646d2SAndroid Build Coastguard Worker 	  _cupsLangPrintFilter(stderr, "ERROR",
762*5e7646d2SAndroid Build Coastguard Worker 	                       _("Unable to send data to printer."));
763*5e7646d2SAndroid Build Coastguard Worker 	  fprintf(stderr, "DEBUG: USB class driver WritePipe returned %x\n",
764*5e7646d2SAndroid Build Coastguard Worker 	          iostatus);
765*5e7646d2SAndroid Build Coastguard Worker 
766*5e7646d2SAndroid Build Coastguard Worker 	  IOReturn err = (*g.classdriver)->Abort(g.classdriver);
767*5e7646d2SAndroid Build Coastguard Worker 	  fprintf(stderr, "DEBUG: USB class driver Abort returned %x\n",
768*5e7646d2SAndroid Build Coastguard Worker 	          err);
769*5e7646d2SAndroid Build Coastguard Worker 
770*5e7646d2SAndroid Build Coastguard Worker 	  status = CUPS_BACKEND_FAILED;
771*5e7646d2SAndroid Build Coastguard Worker 	  break;
772*5e7646d2SAndroid Build Coastguard Worker 	}
773*5e7646d2SAndroid Build Coastguard Worker 	else if (bytes > 0)
774*5e7646d2SAndroid Build Coastguard Worker 	{
775*5e7646d2SAndroid Build Coastguard Worker 	  fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n", (int)bytes);
776*5e7646d2SAndroid Build Coastguard Worker 
777*5e7646d2SAndroid Build Coastguard Worker 	  g.print_bytes -= bytes;
778*5e7646d2SAndroid Build Coastguard Worker 	  print_ptr   += bytes;
779*5e7646d2SAndroid Build Coastguard Worker 	  total_bytes += bytes;
780*5e7646d2SAndroid Build Coastguard Worker 	}
781*5e7646d2SAndroid Build Coastguard Worker       }
782*5e7646d2SAndroid Build Coastguard Worker 
783*5e7646d2SAndroid Build Coastguard Worker       if (print_fd != 0 && status == noErr)
784*5e7646d2SAndroid Build Coastguard Worker 	fprintf(stderr, "DEBUG: Sending print file, %lld bytes...\n",
785*5e7646d2SAndroid Build Coastguard Worker 		(off_t)total_bytes);
786*5e7646d2SAndroid Build Coastguard Worker     }
787*5e7646d2SAndroid Build Coastguard Worker   }
788*5e7646d2SAndroid Build Coastguard Worker 
789*5e7646d2SAndroid Build Coastguard Worker   fprintf(stderr, "DEBUG: Sent %lld bytes...\n", (off_t)total_bytes);
790*5e7646d2SAndroid Build Coastguard Worker   fputs("STATE: +cups-waiting-for-job-completed\n", stderr);
791*5e7646d2SAndroid Build Coastguard Worker 
792*5e7646d2SAndroid Build Coastguard Worker  /*
793*5e7646d2SAndroid Build Coastguard Worker   * Signal the side channel thread to exit...
794*5e7646d2SAndroid Build Coastguard Worker   */
795*5e7646d2SAndroid Build Coastguard Worker 
796*5e7646d2SAndroid Build Coastguard Worker   if (have_sidechannel)
797*5e7646d2SAndroid Build Coastguard Worker   {
798*5e7646d2SAndroid Build Coastguard Worker     close(CUPS_SC_FD);
799*5e7646d2SAndroid Build Coastguard Worker     pthread_mutex_lock(&g.readwrite_lock_mutex);
800*5e7646d2SAndroid Build Coastguard Worker     g.readwrite_lock = 0;
801*5e7646d2SAndroid Build Coastguard Worker     pthread_cond_signal(&g.readwrite_lock_cond);
802*5e7646d2SAndroid Build Coastguard Worker     pthread_mutex_unlock(&g.readwrite_lock_mutex);
803*5e7646d2SAndroid Build Coastguard Worker 
804*5e7646d2SAndroid Build Coastguard Worker     g.sidechannel_thread_stop = 1;
805*5e7646d2SAndroid Build Coastguard Worker     pthread_mutex_lock(&g.sidechannel_thread_mutex);
806*5e7646d2SAndroid Build Coastguard Worker 
807*5e7646d2SAndroid Build Coastguard Worker     if (!g.sidechannel_thread_done)
808*5e7646d2SAndroid Build Coastguard Worker     {
809*5e7646d2SAndroid Build Coastguard Worker       gettimeofday(&tv, NULL);
810*5e7646d2SAndroid Build Coastguard Worker       cond_timeout.tv_sec  = tv.tv_sec + WAIT_SIDE_DELAY;
811*5e7646d2SAndroid Build Coastguard Worker       cond_timeout.tv_nsec = tv.tv_usec * 1000;
812*5e7646d2SAndroid Build Coastguard Worker 
813*5e7646d2SAndroid Build Coastguard Worker       while (!g.sidechannel_thread_done)
814*5e7646d2SAndroid Build Coastguard Worker       {
815*5e7646d2SAndroid Build Coastguard Worker 	if (pthread_cond_timedwait(&g.sidechannel_thread_cond,
816*5e7646d2SAndroid Build Coastguard Worker 				   &g.sidechannel_thread_mutex,
817*5e7646d2SAndroid Build Coastguard Worker 				   &cond_timeout) != 0)
818*5e7646d2SAndroid Build Coastguard Worker 	  break;
819*5e7646d2SAndroid Build Coastguard Worker       }
820*5e7646d2SAndroid Build Coastguard Worker     }
821*5e7646d2SAndroid Build Coastguard Worker 
822*5e7646d2SAndroid Build Coastguard Worker     pthread_mutex_unlock(&g.sidechannel_thread_mutex);
823*5e7646d2SAndroid Build Coastguard Worker   }
824*5e7646d2SAndroid Build Coastguard Worker 
825*5e7646d2SAndroid Build Coastguard Worker  /*
826*5e7646d2SAndroid Build Coastguard Worker   * Signal the read thread to exit then wait 7 seconds for it to complete...
827*5e7646d2SAndroid Build Coastguard Worker   */
828*5e7646d2SAndroid Build Coastguard Worker 
829*5e7646d2SAndroid Build Coastguard Worker   g.read_thread_stop = 1;
830*5e7646d2SAndroid Build Coastguard Worker 
831*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_lock(&g.read_thread_mutex);
832*5e7646d2SAndroid Build Coastguard Worker 
833*5e7646d2SAndroid Build Coastguard Worker   if (!g.read_thread_done)
834*5e7646d2SAndroid Build Coastguard Worker   {
835*5e7646d2SAndroid Build Coastguard Worker     fputs("DEBUG: Waiting for read thread to exit...\n", stderr);
836*5e7646d2SAndroid Build Coastguard Worker 
837*5e7646d2SAndroid Build Coastguard Worker     gettimeofday(&tv, NULL);
838*5e7646d2SAndroid Build Coastguard Worker     cond_timeout.tv_sec  = tv.tv_sec + WAIT_EOF_DELAY;
839*5e7646d2SAndroid Build Coastguard Worker     cond_timeout.tv_nsec = tv.tv_usec * 1000;
840*5e7646d2SAndroid Build Coastguard Worker 
841*5e7646d2SAndroid Build Coastguard Worker     while (!g.read_thread_done)
842*5e7646d2SAndroid Build Coastguard Worker     {
843*5e7646d2SAndroid Build Coastguard Worker       if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex,
844*5e7646d2SAndroid Build Coastguard Worker 				 &cond_timeout) != 0)
845*5e7646d2SAndroid Build Coastguard Worker 	break;
846*5e7646d2SAndroid Build Coastguard Worker     }
847*5e7646d2SAndroid Build Coastguard Worker 
848*5e7646d2SAndroid Build Coastguard Worker    /*
849*5e7646d2SAndroid Build Coastguard Worker     * If it didn't exit abort the pending read and wait an additional second...
850*5e7646d2SAndroid Build Coastguard Worker     */
851*5e7646d2SAndroid Build Coastguard Worker 
852*5e7646d2SAndroid Build Coastguard Worker     if (!g.read_thread_done)
853*5e7646d2SAndroid Build Coastguard Worker     {
854*5e7646d2SAndroid Build Coastguard Worker       fputs("DEBUG: Read thread still active, aborting the pending read...\n",
855*5e7646d2SAndroid Build Coastguard Worker 	    stderr);
856*5e7646d2SAndroid Build Coastguard Worker 
857*5e7646d2SAndroid Build Coastguard Worker       g.wait_eof = 0;
858*5e7646d2SAndroid Build Coastguard Worker 
859*5e7646d2SAndroid Build Coastguard Worker       (*g.classdriver)->Abort(g.classdriver);
860*5e7646d2SAndroid Build Coastguard Worker 
861*5e7646d2SAndroid Build Coastguard Worker       gettimeofday(&tv, NULL);
862*5e7646d2SAndroid Build Coastguard Worker       cond_timeout.tv_sec  = tv.tv_sec + 1;
863*5e7646d2SAndroid Build Coastguard Worker       cond_timeout.tv_nsec = tv.tv_usec * 1000;
864*5e7646d2SAndroid Build Coastguard Worker 
865*5e7646d2SAndroid Build Coastguard Worker       while (!g.read_thread_done)
866*5e7646d2SAndroid Build Coastguard Worker       {
867*5e7646d2SAndroid Build Coastguard Worker 	if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex,
868*5e7646d2SAndroid Build Coastguard Worker 				   &cond_timeout) != 0)
869*5e7646d2SAndroid Build Coastguard Worker 	  break;
870*5e7646d2SAndroid Build Coastguard Worker       }
871*5e7646d2SAndroid Build Coastguard Worker     }
872*5e7646d2SAndroid Build Coastguard Worker   }
873*5e7646d2SAndroid Build Coastguard Worker 
874*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_unlock(&g.read_thread_mutex);
875*5e7646d2SAndroid Build Coastguard Worker 
876*5e7646d2SAndroid Build Coastguard Worker  /*
877*5e7646d2SAndroid Build Coastguard Worker   * Close the connection and input file and general clean up...
878*5e7646d2SAndroid Build Coastguard Worker   */
879*5e7646d2SAndroid Build Coastguard Worker 
880*5e7646d2SAndroid Build Coastguard Worker   registry_close();
881*5e7646d2SAndroid Build Coastguard Worker 
882*5e7646d2SAndroid Build Coastguard Worker   if (print_fd != STDIN_FILENO)
883*5e7646d2SAndroid Build Coastguard Worker     close(print_fd);
884*5e7646d2SAndroid Build Coastguard Worker 
885*5e7646d2SAndroid Build Coastguard Worker   if (g.make != NULL)
886*5e7646d2SAndroid Build Coastguard Worker     CFRelease(g.make);
887*5e7646d2SAndroid Build Coastguard Worker 
888*5e7646d2SAndroid Build Coastguard Worker   if (g.model != NULL)
889*5e7646d2SAndroid Build Coastguard Worker     CFRelease(g.model);
890*5e7646d2SAndroid Build Coastguard Worker 
891*5e7646d2SAndroid Build Coastguard Worker   if (g.serial != NULL)
892*5e7646d2SAndroid Build Coastguard Worker     CFRelease(g.serial);
893*5e7646d2SAndroid Build Coastguard Worker 
894*5e7646d2SAndroid Build Coastguard Worker   if (g.printer_obj != 0x0)
895*5e7646d2SAndroid Build Coastguard Worker     IOObjectRelease(g.printer_obj);
896*5e7646d2SAndroid Build Coastguard Worker 
897*5e7646d2SAndroid Build Coastguard Worker   return status;
898*5e7646d2SAndroid Build Coastguard Worker }
899*5e7646d2SAndroid Build Coastguard Worker 
900*5e7646d2SAndroid Build Coastguard Worker 
901*5e7646d2SAndroid Build Coastguard Worker /*
902*5e7646d2SAndroid Build Coastguard Worker  * 'read_thread()' - Thread to read the backchannel data on.
903*5e7646d2SAndroid Build Coastguard Worker  */
904*5e7646d2SAndroid Build Coastguard Worker 
read_thread(void * reference)905*5e7646d2SAndroid Build Coastguard Worker static void *read_thread(void *reference)
906*5e7646d2SAndroid Build Coastguard Worker {
907*5e7646d2SAndroid Build Coastguard Worker   UInt8				readbuffer[512];
908*5e7646d2SAndroid Build Coastguard Worker   UInt32			rbytes;
909*5e7646d2SAndroid Build Coastguard Worker   kern_return_t			readstatus;
910*5e7646d2SAndroid Build Coastguard Worker   struct mach_timebase_info	timeBaseInfo;
911*5e7646d2SAndroid Build Coastguard Worker   uint64_t			start,
912*5e7646d2SAndroid Build Coastguard Worker 				delay;
913*5e7646d2SAndroid Build Coastguard Worker 
914*5e7646d2SAndroid Build Coastguard Worker 
915*5e7646d2SAndroid Build Coastguard Worker   (void)reference;
916*5e7646d2SAndroid Build Coastguard Worker 
917*5e7646d2SAndroid Build Coastguard Worker   /* Calculate what 250 milliSeconds are in mach absolute time...
918*5e7646d2SAndroid Build Coastguard Worker    */
919*5e7646d2SAndroid Build Coastguard Worker   mach_timebase_info(&timeBaseInfo);
920*5e7646d2SAndroid Build Coastguard Worker   delay = ((uint64_t)250000000 * (uint64_t)timeBaseInfo.denom) / (uint64_t)timeBaseInfo.numer;
921*5e7646d2SAndroid Build Coastguard Worker 
922*5e7646d2SAndroid Build Coastguard Worker   do
923*5e7646d2SAndroid Build Coastguard Worker   {
924*5e7646d2SAndroid Build Coastguard Worker    /*
925*5e7646d2SAndroid Build Coastguard Worker     * Remember when we started so we can throttle the loop after the read call...
926*5e7646d2SAndroid Build Coastguard Worker     */
927*5e7646d2SAndroid Build Coastguard Worker 
928*5e7646d2SAndroid Build Coastguard Worker     start = mach_absolute_time();
929*5e7646d2SAndroid Build Coastguard Worker 
930*5e7646d2SAndroid Build Coastguard Worker     rbytes = sizeof(readbuffer);
931*5e7646d2SAndroid Build Coastguard Worker     readstatus = (*g.classdriver)->ReadPipe(g.classdriver, readbuffer, &rbytes);
932*5e7646d2SAndroid Build Coastguard Worker     if (readstatus == kIOReturnSuccess && rbytes > 0)
933*5e7646d2SAndroid Build Coastguard Worker     {
934*5e7646d2SAndroid Build Coastguard Worker       fprintf(stderr, "DEBUG: Read %d bytes of back-channel data...\n",
935*5e7646d2SAndroid Build Coastguard Worker               (int)rbytes);
936*5e7646d2SAndroid Build Coastguard Worker       cupsBackChannelWrite((char*)readbuffer, rbytes, 1.0);
937*5e7646d2SAndroid Build Coastguard Worker 
938*5e7646d2SAndroid Build Coastguard Worker       /* cntrl-d is echoed by the printer.
939*5e7646d2SAndroid Build Coastguard Worker        * NOTES:
940*5e7646d2SAndroid Build Coastguard Worker        *   Xerox Phaser 6250D doesn't echo the cntrl-d.
941*5e7646d2SAndroid Build Coastguard Worker        *   Xerox Phaser 6250D doesn't always send the product query.
942*5e7646d2SAndroid Build Coastguard Worker        */
943*5e7646d2SAndroid Build Coastguard Worker       if (g.wait_eof && readbuffer[rbytes-1] == 0x4)
944*5e7646d2SAndroid Build Coastguard Worker 	break;
945*5e7646d2SAndroid Build Coastguard Worker 
946*5e7646d2SAndroid Build Coastguard Worker #ifdef PARSE_PS_ERRORS
947*5e7646d2SAndroid Build Coastguard Worker       parse_pserror(readbuffer, rbytes);
948*5e7646d2SAndroid Build Coastguard Worker #endif
949*5e7646d2SAndroid Build Coastguard Worker     }
950*5e7646d2SAndroid Build Coastguard Worker     else if (readstatus == kIOUSBTransactionTimeout)
951*5e7646d2SAndroid Build Coastguard Worker       fputs("DEBUG: Got USB transaction timeout during read\n", stderr);
952*5e7646d2SAndroid Build Coastguard Worker     else if (readstatus == kIOUSBPipeStalled)
953*5e7646d2SAndroid Build Coastguard Worker       fputs("DEBUG: Got USB pipe stalled during read\n", stderr);
954*5e7646d2SAndroid Build Coastguard Worker     else if (readstatus == kIOReturnAborted)
955*5e7646d2SAndroid Build Coastguard Worker       fputs("DEBUG: Got USB return aborted during read\n", stderr);
956*5e7646d2SAndroid Build Coastguard Worker 
957*5e7646d2SAndroid Build Coastguard Worker    /*
958*5e7646d2SAndroid Build Coastguard Worker     * Make sure this loop executes no more than once every 250 miliseconds...
959*5e7646d2SAndroid Build Coastguard Worker     */
960*5e7646d2SAndroid Build Coastguard Worker 
961*5e7646d2SAndroid Build Coastguard Worker     if ((readstatus != kIOReturnSuccess || rbytes == 0) && (g.wait_eof || !g.read_thread_stop))
962*5e7646d2SAndroid Build Coastguard Worker       mach_wait_until(start + delay);
963*5e7646d2SAndroid Build Coastguard Worker 
964*5e7646d2SAndroid Build Coastguard Worker   } while (g.wait_eof || !g.read_thread_stop);	/* Abort from main thread tests error here */
965*5e7646d2SAndroid Build Coastguard Worker 
966*5e7646d2SAndroid Build Coastguard Worker   /* Workaround for usb race condition. <rdar://problem/21882551> */
967*5e7646d2SAndroid Build Coastguard Worker   if (!g.wait_eof && g.use_generic_class_driver)
968*5e7646d2SAndroid Build Coastguard Worker   {
969*5e7646d2SAndroid Build Coastguard Worker      const char *pdl = getenv("FINAL_CONTENT_TYPE");
970*5e7646d2SAndroid Build Coastguard Worker      if (pdl && strcmp(pdl, "application/vnd.cups-postscript") == 0)
971*5e7646d2SAndroid Build Coastguard Worker      {
972*5e7646d2SAndroid Build Coastguard Worker        while (readstatus == kIOReturnSuccess && ((rbytes > 0 && readbuffer[rbytes-1] != 0x4) || rbytes == 0))
973*5e7646d2SAndroid Build Coastguard Worker        {
974*5e7646d2SAndroid Build Coastguard Worker          start = mach_absolute_time();
975*5e7646d2SAndroid Build Coastguard Worker 
976*5e7646d2SAndroid Build Coastguard Worker          rbytes = sizeof(readbuffer);
977*5e7646d2SAndroid Build Coastguard Worker          readstatus = (*g.classdriver)->ReadPipe(g.classdriver, readbuffer, &rbytes);
978*5e7646d2SAndroid Build Coastguard Worker          if (readstatus == kIOReturnSuccess && rbytes > 0 && readbuffer[rbytes-1] == 0x4)
979*5e7646d2SAndroid Build Coastguard Worker            break;
980*5e7646d2SAndroid Build Coastguard Worker 
981*5e7646d2SAndroid Build Coastguard Worker          /* Make sure this loop executes no more than once every 250 miliseconds... */
982*5e7646d2SAndroid Build Coastguard Worker          mach_wait_until(start + delay);
983*5e7646d2SAndroid Build Coastguard Worker        }
984*5e7646d2SAndroid Build Coastguard Worker      }
985*5e7646d2SAndroid Build Coastguard Worker   }
986*5e7646d2SAndroid Build Coastguard Worker 
987*5e7646d2SAndroid Build Coastguard Worker  /*
988*5e7646d2SAndroid Build Coastguard Worker   * Let the main thread know that we have completed the read thread...
989*5e7646d2SAndroid Build Coastguard Worker   */
990*5e7646d2SAndroid Build Coastguard Worker 
991*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_lock(&g.read_thread_mutex);
992*5e7646d2SAndroid Build Coastguard Worker   g.read_thread_done = 1;
993*5e7646d2SAndroid Build Coastguard Worker   pthread_cond_signal(&g.read_thread_cond);
994*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_unlock(&g.read_thread_mutex);
995*5e7646d2SAndroid Build Coastguard Worker 
996*5e7646d2SAndroid Build Coastguard Worker   return NULL;
997*5e7646d2SAndroid Build Coastguard Worker }
998*5e7646d2SAndroid Build Coastguard Worker 
999*5e7646d2SAndroid Build Coastguard Worker 
1000*5e7646d2SAndroid Build Coastguard Worker /*
1001*5e7646d2SAndroid Build Coastguard Worker  * 'sidechannel_thread()' - Handle side-channel requests.
1002*5e7646d2SAndroid Build Coastguard Worker  */
1003*5e7646d2SAndroid Build Coastguard Worker 
1004*5e7646d2SAndroid Build Coastguard Worker static void*
sidechannel_thread(void * reference)1005*5e7646d2SAndroid Build Coastguard Worker sidechannel_thread(void *reference)
1006*5e7646d2SAndroid Build Coastguard Worker {
1007*5e7646d2SAndroid Build Coastguard Worker   cups_sc_command_t	command;	/* Request command */
1008*5e7646d2SAndroid Build Coastguard Worker   cups_sc_status_t	status;		/* Request/response status */
1009*5e7646d2SAndroid Build Coastguard Worker   char			data[2048];	/* Request/response data */
1010*5e7646d2SAndroid Build Coastguard Worker   int			datalen;	/* Request/response data size */
1011*5e7646d2SAndroid Build Coastguard Worker 
1012*5e7646d2SAndroid Build Coastguard Worker 
1013*5e7646d2SAndroid Build Coastguard Worker   (void)reference;
1014*5e7646d2SAndroid Build Coastguard Worker 
1015*5e7646d2SAndroid Build Coastguard Worker   do
1016*5e7646d2SAndroid Build Coastguard Worker   {
1017*5e7646d2SAndroid Build Coastguard Worker     datalen = sizeof(data);
1018*5e7646d2SAndroid Build Coastguard Worker 
1019*5e7646d2SAndroid Build Coastguard Worker     if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
1020*5e7646d2SAndroid Build Coastguard Worker     {
1021*5e7646d2SAndroid Build Coastguard Worker       if (status == CUPS_SC_STATUS_TIMEOUT)
1022*5e7646d2SAndroid Build Coastguard Worker 	continue;
1023*5e7646d2SAndroid Build Coastguard Worker       else
1024*5e7646d2SAndroid Build Coastguard Worker 	break;
1025*5e7646d2SAndroid Build Coastguard Worker     }
1026*5e7646d2SAndroid Build Coastguard Worker 
1027*5e7646d2SAndroid Build Coastguard Worker     switch (command)
1028*5e7646d2SAndroid Build Coastguard Worker     {
1029*5e7646d2SAndroid Build Coastguard Worker       case CUPS_SC_CMD_SOFT_RESET:	/* Do a soft reset */
1030*5e7646d2SAndroid Build Coastguard Worker 	  fputs("DEBUG: CUPS_SC_CMD_SOFT_RESET received from driver...\n",
1031*5e7646d2SAndroid Build Coastguard Worker 		stderr);
1032*5e7646d2SAndroid Build Coastguard Worker 
1033*5e7646d2SAndroid Build Coastguard Worker           if ((*g.classdriver)->SoftReset != NULL)
1034*5e7646d2SAndroid Build Coastguard Worker 	  {
1035*5e7646d2SAndroid Build Coastguard Worker 	    soft_reset();
1036*5e7646d2SAndroid Build Coastguard Worker 	    cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, NULL, 0, 1.0);
1037*5e7646d2SAndroid Build Coastguard Worker 	    fputs("DEBUG: Returning status CUPS_STATUS_OK with no bytes...\n",
1038*5e7646d2SAndroid Build Coastguard Worker 	          stderr);
1039*5e7646d2SAndroid Build Coastguard Worker 	  }
1040*5e7646d2SAndroid Build Coastguard Worker 	  else
1041*5e7646d2SAndroid Build Coastguard Worker 	  {
1042*5e7646d2SAndroid Build Coastguard Worker 	    cupsSideChannelWrite(command, CUPS_SC_STATUS_NOT_IMPLEMENTED,
1043*5e7646d2SAndroid Build Coastguard Worker 	                         NULL, 0, 1.0);
1044*5e7646d2SAndroid Build Coastguard Worker 	    fputs("DEBUG: Returning status CUPS_STATUS_NOT_IMPLEMENTED with "
1045*5e7646d2SAndroid Build Coastguard Worker 	          "no bytes...\n", stderr);
1046*5e7646d2SAndroid Build Coastguard Worker 	  }
1047*5e7646d2SAndroid Build Coastguard Worker 	  break;
1048*5e7646d2SAndroid Build Coastguard Worker 
1049*5e7646d2SAndroid Build Coastguard Worker       case CUPS_SC_CMD_DRAIN_OUTPUT:	/* Drain all pending output */
1050*5e7646d2SAndroid Build Coastguard Worker 	  fputs("DEBUG: CUPS_SC_CMD_DRAIN_OUTPUT received from driver...\n",
1051*5e7646d2SAndroid Build Coastguard Worker 		stderr);
1052*5e7646d2SAndroid Build Coastguard Worker 
1053*5e7646d2SAndroid Build Coastguard Worker 	  g.drain_output = 1;
1054*5e7646d2SAndroid Build Coastguard Worker 	  break;
1055*5e7646d2SAndroid Build Coastguard Worker 
1056*5e7646d2SAndroid Build Coastguard Worker       case CUPS_SC_CMD_GET_BIDI:		/* Is the connection bidirectional? */
1057*5e7646d2SAndroid Build Coastguard Worker 	  fputs("DEBUG: CUPS_SC_CMD_GET_BIDI received from driver...\n",
1058*5e7646d2SAndroid Build Coastguard Worker 		stderr);
1059*5e7646d2SAndroid Build Coastguard Worker 
1060*5e7646d2SAndroid Build Coastguard Worker 	  data[0] = (char)g.bidi_flag;
1061*5e7646d2SAndroid Build Coastguard Worker 	  cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0);
1062*5e7646d2SAndroid Build Coastguard Worker 
1063*5e7646d2SAndroid Build Coastguard Worker 	  fprintf(stderr,
1064*5e7646d2SAndroid Build Coastguard Worker 	          "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n",
1065*5e7646d2SAndroid Build Coastguard Worker 		  data[0]);
1066*5e7646d2SAndroid Build Coastguard Worker 	  break;
1067*5e7646d2SAndroid Build Coastguard Worker 
1068*5e7646d2SAndroid Build Coastguard Worker       case CUPS_SC_CMD_GET_DEVICE_ID:	/* Return IEEE-1284 device ID */
1069*5e7646d2SAndroid Build Coastguard Worker 	  fputs("DEBUG: CUPS_SC_CMD_GET_DEVICE_ID received from driver...\n",
1070*5e7646d2SAndroid Build Coastguard Worker 		stderr);
1071*5e7646d2SAndroid Build Coastguard Worker 
1072*5e7646d2SAndroid Build Coastguard Worker 	  datalen = sizeof(data);
1073*5e7646d2SAndroid Build Coastguard Worker 	  get_device_id(&status, data, &datalen);
1074*5e7646d2SAndroid Build Coastguard Worker 	  cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, datalen, 1.0);
1075*5e7646d2SAndroid Build Coastguard Worker 
1076*5e7646d2SAndroid Build Coastguard Worker           if ((size_t)datalen < sizeof(data))
1077*5e7646d2SAndroid Build Coastguard Worker 	    data[datalen] = '\0';
1078*5e7646d2SAndroid Build Coastguard Worker 	  else
1079*5e7646d2SAndroid Build Coastguard Worker 	    data[sizeof(data) - 1] = '\0';
1080*5e7646d2SAndroid Build Coastguard Worker 
1081*5e7646d2SAndroid Build Coastguard Worker 	  fprintf(stderr,
1082*5e7646d2SAndroid Build Coastguard Worker 	          "DEBUG: Returning CUPS_SC_STATUS_OK with %d bytes (%s)...\n",
1083*5e7646d2SAndroid Build Coastguard Worker 		  datalen, data);
1084*5e7646d2SAndroid Build Coastguard Worker 	  break;
1085*5e7646d2SAndroid Build Coastguard Worker 
1086*5e7646d2SAndroid Build Coastguard Worker       case CUPS_SC_CMD_GET_STATE:		/* Return device state */
1087*5e7646d2SAndroid Build Coastguard Worker 	  fputs("DEBUG: CUPS_SC_CMD_GET_STATE received from driver...\n",
1088*5e7646d2SAndroid Build Coastguard Worker 		stderr);
1089*5e7646d2SAndroid Build Coastguard Worker 
1090*5e7646d2SAndroid Build Coastguard Worker 	  data[0] = CUPS_SC_STATE_ONLINE;
1091*5e7646d2SAndroid Build Coastguard Worker 	  cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0);
1092*5e7646d2SAndroid Build Coastguard Worker 
1093*5e7646d2SAndroid Build Coastguard Worker 	  fprintf(stderr,
1094*5e7646d2SAndroid Build Coastguard Worker 	          "DEBUG: Returned CUPS_SC_STATUS_OK with 1 byte (%02X)...\n",
1095*5e7646d2SAndroid Build Coastguard Worker 		  data[0]);
1096*5e7646d2SAndroid Build Coastguard Worker 	  break;
1097*5e7646d2SAndroid Build Coastguard Worker 
1098*5e7646d2SAndroid Build Coastguard Worker       default:
1099*5e7646d2SAndroid Build Coastguard Worker 	  fprintf(stderr, "DEBUG: Unknown side-channel command (%d) received "
1100*5e7646d2SAndroid Build Coastguard Worker 			  "from driver...\n", command);
1101*5e7646d2SAndroid Build Coastguard Worker 
1102*5e7646d2SAndroid Build Coastguard Worker 	  cupsSideChannelWrite(command, CUPS_SC_STATUS_NOT_IMPLEMENTED,
1103*5e7646d2SAndroid Build Coastguard Worker 			       NULL, 0, 1.0);
1104*5e7646d2SAndroid Build Coastguard Worker 
1105*5e7646d2SAndroid Build Coastguard Worker 	  fputs("DEBUG: Returned CUPS_SC_STATUS_NOT_IMPLEMENTED with no bytes...\n",
1106*5e7646d2SAndroid Build Coastguard Worker 		stderr);
1107*5e7646d2SAndroid Build Coastguard Worker 	  break;
1108*5e7646d2SAndroid Build Coastguard Worker     }
1109*5e7646d2SAndroid Build Coastguard Worker   }
1110*5e7646d2SAndroid Build Coastguard Worker   while (!g.sidechannel_thread_stop);
1111*5e7646d2SAndroid Build Coastguard Worker 
1112*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_lock(&g.sidechannel_thread_mutex);
1113*5e7646d2SAndroid Build Coastguard Worker   g.sidechannel_thread_done = 1;
1114*5e7646d2SAndroid Build Coastguard Worker   pthread_cond_signal(&g.sidechannel_thread_cond);
1115*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_unlock(&g.sidechannel_thread_mutex);
1116*5e7646d2SAndroid Build Coastguard Worker 
1117*5e7646d2SAndroid Build Coastguard Worker   return NULL;
1118*5e7646d2SAndroid Build Coastguard Worker }
1119*5e7646d2SAndroid Build Coastguard Worker 
1120*5e7646d2SAndroid Build Coastguard Worker 
1121*5e7646d2SAndroid Build Coastguard Worker #pragma mark -
1122*5e7646d2SAndroid Build Coastguard Worker /*
1123*5e7646d2SAndroid Build Coastguard Worker  * 'iterate_printers()' - Iterate over all the printers.
1124*5e7646d2SAndroid Build Coastguard Worker  */
iterate_printers(iterator_callback_t callBack,void * userdata)1125*5e7646d2SAndroid Build Coastguard Worker static void iterate_printers(iterator_callback_t callBack, void *userdata)
1126*5e7646d2SAndroid Build Coastguard Worker {
1127*5e7646d2SAndroid Build Coastguard Worker   Iterating = 1;
1128*5e7646d2SAndroid Build Coastguard Worker 
1129*5e7646d2SAndroid Build Coastguard Worker   iterator_reference_t reference = { callBack, userdata, true };
1130*5e7646d2SAndroid Build Coastguard Worker 
1131*5e7646d2SAndroid Build Coastguard Worker   IONotificationPortRef addNotification = IONotificationPortCreate(kIOMasterPortDefault);
1132*5e7646d2SAndroid Build Coastguard Worker 
1133*5e7646d2SAndroid Build Coastguard Worker   int printingClass = kUSBPrintingClass;
1134*5e7646d2SAndroid Build Coastguard Worker   int printingSubclass = kUSBPrintingSubclass;
1135*5e7646d2SAndroid Build Coastguard Worker 
1136*5e7646d2SAndroid Build Coastguard Worker   CFNumberRef interfaceClass = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &printingClass);
1137*5e7646d2SAndroid Build Coastguard Worker   CFNumberRef interfaceSubClass = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &printingSubclass);
1138*5e7646d2SAndroid Build Coastguard Worker 
1139*5e7646d2SAndroid Build Coastguard Worker   CFMutableDictionaryRef usbPrinterMatchDictionary = IOServiceMatching(kIOUSBInterfaceClassName);
1140*5e7646d2SAndroid Build Coastguard Worker   CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceClass"), interfaceClass);
1141*5e7646d2SAndroid Build Coastguard Worker   CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceSubClass"), interfaceSubClass);
1142*5e7646d2SAndroid Build Coastguard Worker 
1143*5e7646d2SAndroid Build Coastguard Worker   CFRelease(interfaceClass);
1144*5e7646d2SAndroid Build Coastguard Worker   CFRelease(interfaceSubClass);
1145*5e7646d2SAndroid Build Coastguard Worker 
1146*5e7646d2SAndroid Build Coastguard Worker   io_iterator_t add_iterator = IO_OBJECT_NULL;
1147*5e7646d2SAndroid Build Coastguard Worker   IOServiceAddMatchingNotification(addNotification, kIOMatchedNotification,
1148*5e7646d2SAndroid Build Coastguard Worker                 usbPrinterMatchDictionary, &device_added, &reference, &add_iterator);
1149*5e7646d2SAndroid Build Coastguard Worker   if (add_iterator != IO_OBJECT_NULL)
1150*5e7646d2SAndroid Build Coastguard Worker   {
1151*5e7646d2SAndroid Build Coastguard Worker     device_added (&reference, add_iterator);
1152*5e7646d2SAndroid Build Coastguard Worker     if (reference.keepRunning)
1153*5e7646d2SAndroid Build Coastguard Worker     {
1154*5e7646d2SAndroid Build Coastguard Worker       CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(addNotification), kCFRunLoopDefaultMode);
1155*5e7646d2SAndroid Build Coastguard Worker       CFRunLoopRun();
1156*5e7646d2SAndroid Build Coastguard Worker     }
1157*5e7646d2SAndroid Build Coastguard Worker     IOObjectRelease(add_iterator);
1158*5e7646d2SAndroid Build Coastguard Worker   }
1159*5e7646d2SAndroid Build Coastguard Worker   Iterating = 0;
1160*5e7646d2SAndroid Build Coastguard Worker }
1161*5e7646d2SAndroid Build Coastguard Worker 
1162*5e7646d2SAndroid Build Coastguard Worker 
1163*5e7646d2SAndroid Build Coastguard Worker /*
1164*5e7646d2SAndroid Build Coastguard Worker  * 'device_added()' - Device added notifier.
1165*5e7646d2SAndroid Build Coastguard Worker  */
device_added(void * userdata,io_iterator_t iterator)1166*5e7646d2SAndroid Build Coastguard Worker static void device_added(void *userdata, io_iterator_t iterator)
1167*5e7646d2SAndroid Build Coastguard Worker {
1168*5e7646d2SAndroid Build Coastguard Worker   iterator_reference_t *reference = userdata;
1169*5e7646d2SAndroid Build Coastguard Worker   io_service_t intf;
1170*5e7646d2SAndroid Build Coastguard Worker 
1171*5e7646d2SAndroid Build Coastguard Worker   while (reference->keepRunning && (intf = IOIteratorNext(iterator)) != 0x0)
1172*5e7646d2SAndroid Build Coastguard Worker   {
1173*5e7646d2SAndroid Build Coastguard Worker     printer_interface_t printerIntf = usb_printer_interface_interface(intf);
1174*5e7646d2SAndroid Build Coastguard Worker     if (printerIntf != NULL)
1175*5e7646d2SAndroid Build Coastguard Worker     {
1176*5e7646d2SAndroid Build Coastguard Worker       UInt8 intfClass = 0, intfSubClass = 0;
1177*5e7646d2SAndroid Build Coastguard Worker 
1178*5e7646d2SAndroid Build Coastguard Worker       (*printerIntf)->GetInterfaceClass(printerIntf, &intfClass);
1179*5e7646d2SAndroid Build Coastguard Worker       (*printerIntf)->GetInterfaceSubClass(printerIntf, &intfSubClass);
1180*5e7646d2SAndroid Build Coastguard Worker       if (intfClass == kUSBPrintingInterfaceClass && intfSubClass == kUSBPrintingSubclass)
1181*5e7646d2SAndroid Build Coastguard Worker         reference->keepRunning = reference->callback(intf, printerIntf, userdata);
1182*5e7646d2SAndroid Build Coastguard Worker         (*printerIntf)->Release(printerIntf);
1183*5e7646d2SAndroid Build Coastguard Worker       }
1184*5e7646d2SAndroid Build Coastguard Worker       IOObjectRelease(intf);
1185*5e7646d2SAndroid Build Coastguard Worker     }
1186*5e7646d2SAndroid Build Coastguard Worker 
1187*5e7646d2SAndroid Build Coastguard Worker     if (reference->keepRunning && reference->callback)
1188*5e7646d2SAndroid Build Coastguard Worker       reference->keepRunning = reference->callback(IO_OBJECT_NULL, NULL, reference->userdata);
1189*5e7646d2SAndroid Build Coastguard Worker 
1190*5e7646d2SAndroid Build Coastguard Worker     if (!reference->keepRunning)
1191*5e7646d2SAndroid Build Coastguard Worker       CFRunLoopStop(CFRunLoopGetCurrent());
1192*5e7646d2SAndroid Build Coastguard Worker }
1193*5e7646d2SAndroid Build Coastguard Worker 
1194*5e7646d2SAndroid Build Coastguard Worker /*
1195*5e7646d2SAndroid Build Coastguard Worker  * 'list_device_cb()' - list_device iterator callback.
1196*5e7646d2SAndroid Build Coastguard Worker  */
list_device_cb(io_service_t obj,printer_interface_t printerIntf,void * refcon)1197*5e7646d2SAndroid Build Coastguard Worker static Boolean list_device_cb(io_service_t obj, printer_interface_t printerIntf, void *refcon)
1198*5e7646d2SAndroid Build Coastguard Worker {
1199*5e7646d2SAndroid Build Coastguard Worker   (void)refcon;
1200*5e7646d2SAndroid Build Coastguard Worker 
1201*5e7646d2SAndroid Build Coastguard Worker   if (obj != IO_OBJECT_NULL)
1202*5e7646d2SAndroid Build Coastguard Worker   {
1203*5e7646d2SAndroid Build Coastguard Worker     CFStringRef deviceIDString = NULL;
1204*5e7646d2SAndroid Build Coastguard Worker     CFStringRef make = NULL;
1205*5e7646d2SAndroid Build Coastguard Worker     CFStringRef model = NULL;
1206*5e7646d2SAndroid Build Coastguard Worker     CFStringRef serial = NULL;
1207*5e7646d2SAndroid Build Coastguard Worker     UInt32 intfLocation;
1208*5e7646d2SAndroid Build Coastguard Worker 
1209*5e7646d2SAndroid Build Coastguard Worker     deviceIDString = copy_printer_interface_deviceid(printerIntf, 0);
1210*5e7646d2SAndroid Build Coastguard Worker     if (deviceIDString == NULL)
1211*5e7646d2SAndroid Build Coastguard Worker       goto list_device_done;
1212*5e7646d2SAndroid Build Coastguard Worker 
1213*5e7646d2SAndroid Build Coastguard Worker     make = deviceIDCopyManufacturer(deviceIDString);
1214*5e7646d2SAndroid Build Coastguard Worker     model = deviceIDCopyModel(deviceIDString);
1215*5e7646d2SAndroid Build Coastguard Worker     serial = deviceIDCopySerialNumber(deviceIDString);
1216*5e7646d2SAndroid Build Coastguard Worker 
1217*5e7646d2SAndroid Build Coastguard Worker     char uristr[1024], makestr[1024], modelstr[1024], serialstr[1024];
1218*5e7646d2SAndroid Build Coastguard Worker     char optionsstr[1024], idstr[1024], make_modelstr[1024];
1219*5e7646d2SAndroid Build Coastguard Worker 
1220*5e7646d2SAndroid Build Coastguard Worker     CFStringGetCString(deviceIDString, idstr, sizeof(idstr), kCFStringEncodingUTF8);
1221*5e7646d2SAndroid Build Coastguard Worker     backendGetMakeModel(idstr, make_modelstr, sizeof(make_modelstr));
1222*5e7646d2SAndroid Build Coastguard Worker 
1223*5e7646d2SAndroid Build Coastguard Worker     modelstr[0] = '/';
1224*5e7646d2SAndroid Build Coastguard Worker 
1225*5e7646d2SAndroid Build Coastguard Worker     if (make  == NULL || !CFStringGetCString(make, makestr, sizeof(makestr), kCFStringEncodingUTF8))
1226*5e7646d2SAndroid Build Coastguard Worker       strlcpy(makestr, "Unknown", sizeof(makestr));
1227*5e7646d2SAndroid Build Coastguard Worker 
1228*5e7646d2SAndroid Build Coastguard Worker     if (model == NULL || !CFStringGetCString(model, &modelstr[1], sizeof(modelstr)-1, kCFStringEncodingUTF8))
1229*5e7646d2SAndroid Build Coastguard Worker       strlcpy(modelstr + 1, "Printer", sizeof(modelstr) - 1);
1230*5e7646d2SAndroid Build Coastguard Worker 
1231*5e7646d2SAndroid Build Coastguard Worker     optionsstr[0] = '\0';
1232*5e7646d2SAndroid Build Coastguard Worker     if (serial != NULL && CFStringGetCString(serial, serialstr, sizeof(serialstr), kCFStringEncodingUTF8))
1233*5e7646d2SAndroid Build Coastguard Worker       snprintf(optionsstr, sizeof(optionsstr), "?serial=%s", serialstr);
1234*5e7646d2SAndroid Build Coastguard Worker     else if ((*printerIntf)->GetLocationID(printerIntf, &intfLocation) == kIOReturnSuccess)
1235*5e7646d2SAndroid Build Coastguard Worker       snprintf(optionsstr, sizeof(optionsstr), "?location=%x", (unsigned)intfLocation);
1236*5e7646d2SAndroid Build Coastguard Worker 
1237*5e7646d2SAndroid Build Coastguard Worker     httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
1238*5e7646d2SAndroid Build Coastguard Worker     strlcat(uristr, optionsstr, sizeof(uristr));
1239*5e7646d2SAndroid Build Coastguard Worker 
1240*5e7646d2SAndroid Build Coastguard Worker     cupsBackendReport("direct", uristr, make_modelstr, make_modelstr, idstr,
1241*5e7646d2SAndroid Build Coastguard Worker                           NULL);
1242*5e7646d2SAndroid Build Coastguard Worker   list_device_done:
1243*5e7646d2SAndroid Build Coastguard Worker 
1244*5e7646d2SAndroid Build Coastguard Worker     if (make != NULL) CFRelease(make);
1245*5e7646d2SAndroid Build Coastguard Worker     if (model != NULL) CFRelease(model);
1246*5e7646d2SAndroid Build Coastguard Worker     if (serial != NULL) CFRelease(serial);
1247*5e7646d2SAndroid Build Coastguard Worker   }
1248*5e7646d2SAndroid Build Coastguard Worker   return obj != IO_OBJECT_NULL;
1249*5e7646d2SAndroid Build Coastguard Worker }
1250*5e7646d2SAndroid Build Coastguard Worker 
1251*5e7646d2SAndroid Build Coastguard Worker /*
1252*5e7646d2SAndroid Build Coastguard Worker  * 'find_device_cb()' - print_device iterator callback.
1253*5e7646d2SAndroid Build Coastguard Worker  */
find_device_cb(io_service_t obj,printer_interface_t printerIntf,void * refcon)1254*5e7646d2SAndroid Build Coastguard Worker static Boolean find_device_cb(io_service_t obj, printer_interface_t printerIntf, void *refcon)
1255*5e7646d2SAndroid Build Coastguard Worker {
1256*5e7646d2SAndroid Build Coastguard Worker   (void)refcon;
1257*5e7646d2SAndroid Build Coastguard Worker 
1258*5e7646d2SAndroid Build Coastguard Worker   Boolean keepLooking = true;
1259*5e7646d2SAndroid Build Coastguard Worker 
1260*5e7646d2SAndroid Build Coastguard Worker   if (obj != IO_OBJECT_NULL)
1261*5e7646d2SAndroid Build Coastguard Worker   {
1262*5e7646d2SAndroid Build Coastguard Worker     CFStringRef deviceIDString = NULL;
1263*5e7646d2SAndroid Build Coastguard Worker     CFStringRef make = NULL;
1264*5e7646d2SAndroid Build Coastguard Worker     CFStringRef model = NULL;
1265*5e7646d2SAndroid Build Coastguard Worker     CFStringRef serial = NULL;
1266*5e7646d2SAndroid Build Coastguard Worker 
1267*5e7646d2SAndroid Build Coastguard Worker     deviceIDString = copy_printer_interface_deviceid(printerIntf, 0);
1268*5e7646d2SAndroid Build Coastguard Worker     if (deviceIDString == NULL)
1269*5e7646d2SAndroid Build Coastguard Worker       goto find_device_done;
1270*5e7646d2SAndroid Build Coastguard Worker 
1271*5e7646d2SAndroid Build Coastguard Worker     make = deviceIDCopyManufacturer(deviceIDString);
1272*5e7646d2SAndroid Build Coastguard Worker     model = deviceIDCopyModel(deviceIDString);
1273*5e7646d2SAndroid Build Coastguard Worker     serial = deviceIDCopySerialNumber(deviceIDString);
1274*5e7646d2SAndroid Build Coastguard Worker 
1275*5e7646d2SAndroid Build Coastguard Worker     if (make && CFStringCompare(make, g.make, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
1276*5e7646d2SAndroid Build Coastguard Worker     {
1277*5e7646d2SAndroid Build Coastguard Worker       if (model && CFStringCompare(model, g.model, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
1278*5e7646d2SAndroid Build Coastguard Worker       {
1279*5e7646d2SAndroid Build Coastguard Worker         UInt8 intfAltSetting = 0, intfNumber = 0, intfProtocol = 0;
1280*5e7646d2SAndroid Build Coastguard Worker         UInt32 intfLocation = 0;
1281*5e7646d2SAndroid Build Coastguard Worker 
1282*5e7646d2SAndroid Build Coastguard Worker         (*printerIntf)->GetInterfaceProtocol(printerIntf, &intfProtocol);
1283*5e7646d2SAndroid Build Coastguard Worker         (*printerIntf)->GetAlternateSetting(printerIntf, &intfAltSetting);
1284*5e7646d2SAndroid Build Coastguard Worker         (*printerIntf)->GetInterfaceNumber(printerIntf, &intfNumber);
1285*5e7646d2SAndroid Build Coastguard Worker         (*printerIntf)->GetLocationID(printerIntf, &intfLocation);
1286*5e7646d2SAndroid Build Coastguard Worker 
1287*5e7646d2SAndroid Build Coastguard Worker         if (intfProtocol == kUSBPrintingProtocolIPP)
1288*5e7646d2SAndroid Build Coastguard Worker             return keepLooking;
1289*5e7646d2SAndroid Build Coastguard Worker 
1290*5e7646d2SAndroid Build Coastguard Worker         if (g.serial != NULL && CFStringGetLength(g.serial) > 0)
1291*5e7646d2SAndroid Build Coastguard Worker         {
1292*5e7646d2SAndroid Build Coastguard Worker           if (serial != NULL && CFStringCompare(serial, g.serial, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
1293*5e7646d2SAndroid Build Coastguard Worker           {
1294*5e7646d2SAndroid Build Coastguard Worker             g.interfaceProtocol = intfProtocol;
1295*5e7646d2SAndroid Build Coastguard Worker             g.location = intfLocation;
1296*5e7646d2SAndroid Build Coastguard Worker             g.alternateSetting = intfAltSetting;
1297*5e7646d2SAndroid Build Coastguard Worker             g.printer_obj = obj;
1298*5e7646d2SAndroid Build Coastguard Worker             IOObjectRetain(obj);
1299*5e7646d2SAndroid Build Coastguard Worker             keepLooking = false;
1300*5e7646d2SAndroid Build Coastguard Worker           }
1301*5e7646d2SAndroid Build Coastguard Worker         }
1302*5e7646d2SAndroid Build Coastguard Worker         else
1303*5e7646d2SAndroid Build Coastguard Worker         {
1304*5e7646d2SAndroid Build Coastguard Worker           if (g.printer_obj != 0)
1305*5e7646d2SAndroid Build Coastguard Worker             IOObjectRelease(g.printer_obj);
1306*5e7646d2SAndroid Build Coastguard Worker 
1307*5e7646d2SAndroid Build Coastguard Worker             if (g.location == 0 || g.location == intfLocation)
1308*5e7646d2SAndroid Build Coastguard Worker                 keepLooking = false;
1309*5e7646d2SAndroid Build Coastguard Worker 
1310*5e7646d2SAndroid Build Coastguard Worker             g.location = intfLocation;
1311*5e7646d2SAndroid Build Coastguard Worker             g.alternateSetting = intfAltSetting;
1312*5e7646d2SAndroid Build Coastguard Worker             g.interfaceProtocol = intfProtocol;
1313*5e7646d2SAndroid Build Coastguard Worker             g.printer_obj = obj;
1314*5e7646d2SAndroid Build Coastguard Worker             IOObjectRetain(obj);
1315*5e7646d2SAndroid Build Coastguard Worker         }
1316*5e7646d2SAndroid Build Coastguard Worker 
1317*5e7646d2SAndroid Build Coastguard Worker         if (!keepLooking)
1318*5e7646d2SAndroid Build Coastguard Worker           g.interfaceNum = intfNumber;
1319*5e7646d2SAndroid Build Coastguard Worker       }
1320*5e7646d2SAndroid Build Coastguard Worker     }
1321*5e7646d2SAndroid Build Coastguard Worker 
1322*5e7646d2SAndroid Build Coastguard Worker   find_device_done:
1323*5e7646d2SAndroid Build Coastguard Worker     if (deviceIDString != NULL) CFRelease(deviceIDString);
1324*5e7646d2SAndroid Build Coastguard Worker     if (make != NULL) CFRelease(make);
1325*5e7646d2SAndroid Build Coastguard Worker     if (model != NULL) CFRelease(model);
1326*5e7646d2SAndroid Build Coastguard Worker     if (serial != NULL) CFRelease(serial);
1327*5e7646d2SAndroid Build Coastguard Worker   }
1328*5e7646d2SAndroid Build Coastguard Worker   else
1329*5e7646d2SAndroid Build Coastguard Worker   {
1330*5e7646d2SAndroid Build Coastguard Worker     keepLooking = (g.printer_obj == 0 && g.interfaceProtocol != kUSBPrintingProtocolIPP);
1331*5e7646d2SAndroid Build Coastguard Worker     if (obj == IO_OBJECT_NULL && keepLooking)
1332*5e7646d2SAndroid Build Coastguard Worker     {
1333*5e7646d2SAndroid Build Coastguard Worker       CFRunLoopTimerContext context = { 0, refcon, NULL, NULL, NULL };
1334*5e7646d2SAndroid Build Coastguard Worker       CFRunLoopTimerRef timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + 1.0, 10, 0x0, 0x0, status_timer_cb, &context);
1335*5e7646d2SAndroid Build Coastguard Worker       if (timer != NULL)
1336*5e7646d2SAndroid Build Coastguard Worker       {
1337*5e7646d2SAndroid Build Coastguard Worker         CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
1338*5e7646d2SAndroid Build Coastguard Worker         g.status_timer = timer;
1339*5e7646d2SAndroid Build Coastguard Worker       }
1340*5e7646d2SAndroid Build Coastguard Worker     }
1341*5e7646d2SAndroid Build Coastguard Worker   }
1342*5e7646d2SAndroid Build Coastguard Worker 
1343*5e7646d2SAndroid Build Coastguard Worker   if (!keepLooking && g.status_timer != NULL)
1344*5e7646d2SAndroid Build Coastguard Worker   {
1345*5e7646d2SAndroid Build Coastguard Worker     fputs("STATE: -offline-report\n", stderr);
1346*5e7646d2SAndroid Build Coastguard Worker     _cupsLangPrintFilter(stderr, "INFO", _("The printer is now online."));
1347*5e7646d2SAndroid Build Coastguard Worker     CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), g.status_timer, kCFRunLoopDefaultMode);
1348*5e7646d2SAndroid Build Coastguard Worker     CFRelease(g.status_timer);
1349*5e7646d2SAndroid Build Coastguard Worker     g.status_timer = NULL;
1350*5e7646d2SAndroid Build Coastguard Worker   }
1351*5e7646d2SAndroid Build Coastguard Worker 
1352*5e7646d2SAndroid Build Coastguard Worker   return keepLooking;
1353*5e7646d2SAndroid Build Coastguard Worker }
1354*5e7646d2SAndroid Build Coastguard Worker 
deviceIDCopySerialNumber(CFStringRef deviceID)1355*5e7646d2SAndroid Build Coastguard Worker static CFStringRef deviceIDCopySerialNumber(CFStringRef deviceID)
1356*5e7646d2SAndroid Build Coastguard Worker {
1357*5e7646d2SAndroid Build Coastguard Worker     CFStringRef serialKeys[] = { CFSTR("SN:"),  CFSTR("SERN:"), NULL };
1358*5e7646d2SAndroid Build Coastguard Worker 
1359*5e7646d2SAndroid Build Coastguard Worker     return copy_value_for_key(deviceID, serialKeys);
1360*5e7646d2SAndroid Build Coastguard Worker }
1361*5e7646d2SAndroid Build Coastguard Worker 
deviceIDCopyModel(CFStringRef deviceID)1362*5e7646d2SAndroid Build Coastguard Worker static CFStringRef deviceIDCopyModel(CFStringRef deviceID)
1363*5e7646d2SAndroid Build Coastguard Worker {
1364*5e7646d2SAndroid Build Coastguard Worker     CFStringRef modelKeys[] = { CFSTR("MDL:"), CFSTR("MODEL:"), NULL };
1365*5e7646d2SAndroid Build Coastguard Worker     return copy_value_for_key(deviceID, modelKeys);
1366*5e7646d2SAndroid Build Coastguard Worker }
1367*5e7646d2SAndroid Build Coastguard Worker 
deviceIDCopyManufacturer(CFStringRef deviceID)1368*5e7646d2SAndroid Build Coastguard Worker static CFStringRef deviceIDCopyManufacturer(CFStringRef deviceID)
1369*5e7646d2SAndroid Build Coastguard Worker {
1370*5e7646d2SAndroid Build Coastguard Worker     CFStringRef makeKeys[]   = { CFSTR("MFG:"), CFSTR("MANUFACTURER:"), NULL };
1371*5e7646d2SAndroid Build Coastguard Worker     return copy_value_for_key(deviceID, makeKeys);
1372*5e7646d2SAndroid Build Coastguard Worker }
1373*5e7646d2SAndroid Build Coastguard Worker 
1374*5e7646d2SAndroid Build Coastguard Worker /*
1375*5e7646d2SAndroid Build Coastguard Worker  * 'status_timer_cb()' - Status timer callback.
1376*5e7646d2SAndroid Build Coastguard Worker  */
1377*5e7646d2SAndroid Build Coastguard Worker 
status_timer_cb(CFRunLoopTimerRef timer,void * info)1378*5e7646d2SAndroid Build Coastguard Worker static void status_timer_cb(CFRunLoopTimerRef timer,
1379*5e7646d2SAndroid Build Coastguard Worker 			    void *info)
1380*5e7646d2SAndroid Build Coastguard Worker {
1381*5e7646d2SAndroid Build Coastguard Worker   (void)timer;
1382*5e7646d2SAndroid Build Coastguard Worker   (void)info;
1383*5e7646d2SAndroid Build Coastguard Worker 
1384*5e7646d2SAndroid Build Coastguard Worker   fputs("STATE: +offline-report\n", stderr);
1385*5e7646d2SAndroid Build Coastguard Worker   _cupsLangPrintFilter(stderr, "INFO", _("The printer is offline."));
1386*5e7646d2SAndroid Build Coastguard Worker 
1387*5e7646d2SAndroid Build Coastguard Worker   if (getenv("CLASS") != NULL)
1388*5e7646d2SAndroid Build Coastguard Worker   {
1389*5e7646d2SAndroid Build Coastguard Worker    /*
1390*5e7646d2SAndroid Build Coastguard Worker     * If the CLASS environment variable is set, the job was submitted
1391*5e7646d2SAndroid Build Coastguard Worker     * to a class and not to a specific queue.  In this case, we want
1392*5e7646d2SAndroid Build Coastguard Worker     * to abort immediately so that the job can be requeued on the next
1393*5e7646d2SAndroid Build Coastguard Worker     * available printer in the class.
1394*5e7646d2SAndroid Build Coastguard Worker     *
1395*5e7646d2SAndroid Build Coastguard Worker     * Sleep 5 seconds to keep the job from requeuing too rapidly...
1396*5e7646d2SAndroid Build Coastguard Worker     */
1397*5e7646d2SAndroid Build Coastguard Worker 
1398*5e7646d2SAndroid Build Coastguard Worker     sleep(5);
1399*5e7646d2SAndroid Build Coastguard Worker 
1400*5e7646d2SAndroid Build Coastguard Worker     exit(CUPS_BACKEND_FAILED);
1401*5e7646d2SAndroid Build Coastguard Worker   }
1402*5e7646d2SAndroid Build Coastguard Worker }
1403*5e7646d2SAndroid Build Coastguard Worker 
1404*5e7646d2SAndroid Build Coastguard Worker 
1405*5e7646d2SAndroid Build Coastguard Worker #pragma mark -
1406*5e7646d2SAndroid Build Coastguard Worker /*
1407*5e7646d2SAndroid Build Coastguard Worker  * 'load_classdriver()' - Load a classdriver.
1408*5e7646d2SAndroid Build Coastguard Worker  */
1409*5e7646d2SAndroid Build Coastguard Worker 
load_classdriver(CFStringRef driverPath,printer_interface_t interface,classdriver_t *** printerDriver)1410*5e7646d2SAndroid Build Coastguard Worker static kern_return_t load_classdriver(CFStringRef	    driverPath,
1411*5e7646d2SAndroid Build Coastguard Worker 				      printer_interface_t   interface,
1412*5e7646d2SAndroid Build Coastguard Worker 				      classdriver_t	    ***printerDriver)
1413*5e7646d2SAndroid Build Coastguard Worker {
1414*5e7646d2SAndroid Build Coastguard Worker   kern_return_t	kr = kUSBPrinterClassDeviceNotOpen;
1415*5e7646d2SAndroid Build Coastguard Worker   classdriver_t	**driver = NULL;
1416*5e7646d2SAndroid Build Coastguard Worker   CFStringRef	bundle = driverPath ? driverPath : kUSBGenericTOPrinterClassDriver;
1417*5e7646d2SAndroid Build Coastguard Worker   char 		bundlestr[1024];	/* Bundle path */
1418*5e7646d2SAndroid Build Coastguard Worker   CFURLRef	url;			/* URL for driver */
1419*5e7646d2SAndroid Build Coastguard Worker   CFPlugInRef	plugin = NULL;		/* Plug-in address */
1420*5e7646d2SAndroid Build Coastguard Worker 
1421*5e7646d2SAndroid Build Coastguard Worker 
1422*5e7646d2SAndroid Build Coastguard Worker   CFStringGetCString(bundle, bundlestr, sizeof(bundlestr), kCFStringEncodingUTF8);
1423*5e7646d2SAndroid Build Coastguard Worker 
1424*5e7646d2SAndroid Build Coastguard Worker  /*
1425*5e7646d2SAndroid Build Coastguard Worker   * Validate permissions for the class driver...
1426*5e7646d2SAndroid Build Coastguard Worker   */
1427*5e7646d2SAndroid Build Coastguard Worker 
1428*5e7646d2SAndroid Build Coastguard Worker   _cups_fc_result_t result = _cupsFileCheck(bundlestr,
1429*5e7646d2SAndroid Build Coastguard Worker                                             _CUPS_FILE_CHECK_DIRECTORY, 1,
1430*5e7646d2SAndroid Build Coastguard Worker                                             Iterating ? NULL : _cupsFileCheckFilter, NULL);
1431*5e7646d2SAndroid Build Coastguard Worker 
1432*5e7646d2SAndroid Build Coastguard Worker   if (result && driverPath)
1433*5e7646d2SAndroid Build Coastguard Worker     return (load_classdriver(NULL, interface, printerDriver));
1434*5e7646d2SAndroid Build Coastguard Worker   else if (result)
1435*5e7646d2SAndroid Build Coastguard Worker     return (kr);
1436*5e7646d2SAndroid Build Coastguard Worker 
1437*5e7646d2SAndroid Build Coastguard Worker  /*
1438*5e7646d2SAndroid Build Coastguard Worker   * Try loading the class driver...
1439*5e7646d2SAndroid Build Coastguard Worker   */
1440*5e7646d2SAndroid Build Coastguard Worker 
1441*5e7646d2SAndroid Build Coastguard Worker   url = CFURLCreateWithFileSystemPath(NULL, bundle, kCFURLPOSIXPathStyle, true);
1442*5e7646d2SAndroid Build Coastguard Worker 
1443*5e7646d2SAndroid Build Coastguard Worker   if (url)
1444*5e7646d2SAndroid Build Coastguard Worker   {
1445*5e7646d2SAndroid Build Coastguard Worker     plugin = CFPlugInCreate(NULL, url);
1446*5e7646d2SAndroid Build Coastguard Worker     CFRelease(url);
1447*5e7646d2SAndroid Build Coastguard Worker   }
1448*5e7646d2SAndroid Build Coastguard Worker   else
1449*5e7646d2SAndroid Build Coastguard Worker     plugin = NULL;
1450*5e7646d2SAndroid Build Coastguard Worker 
1451*5e7646d2SAndroid Build Coastguard Worker   if (plugin)
1452*5e7646d2SAndroid Build Coastguard Worker   {
1453*5e7646d2SAndroid Build Coastguard Worker     CFArrayRef factories = CFPlugInFindFactoriesForPlugInTypeInPlugIn(kUSBPrinterClassTypeID, plugin);
1454*5e7646d2SAndroid Build Coastguard Worker     if (factories != NULL && CFArrayGetCount(factories) > 0)
1455*5e7646d2SAndroid Build Coastguard Worker     {
1456*5e7646d2SAndroid Build Coastguard Worker       CFUUIDRef factoryID = CFArrayGetValueAtIndex(factories, 0);
1457*5e7646d2SAndroid Build Coastguard Worker       IUnknownVTbl **iunknown = CFPlugInInstanceCreate(NULL, factoryID, kUSBPrinterClassTypeID);
1458*5e7646d2SAndroid Build Coastguard Worker       if (iunknown != NULL)
1459*5e7646d2SAndroid Build Coastguard Worker       {
1460*5e7646d2SAndroid Build Coastguard Worker 	kr = (*iunknown)->QueryInterface(iunknown, CFUUIDGetUUIDBytes(kUSBPrinterClassInterfaceID), (LPVOID *)&driver);
1461*5e7646d2SAndroid Build Coastguard Worker 	if (kr == kIOReturnSuccess && driver != NULL)
1462*5e7646d2SAndroid Build Coastguard Worker 	{
1463*5e7646d2SAndroid Build Coastguard Worker 	  classdriver_t **genericDriver = NULL;
1464*5e7646d2SAndroid Build Coastguard Worker 	  if (driverPath != NULL && CFStringCompare(driverPath, kUSBGenericTOPrinterClassDriver, 0) != kCFCompareEqualTo)
1465*5e7646d2SAndroid Build Coastguard Worker 	    kr = load_classdriver(NULL, interface, &genericDriver);
1466*5e7646d2SAndroid Build Coastguard Worker 
1467*5e7646d2SAndroid Build Coastguard Worker 	  if (kr == kIOReturnSuccess)
1468*5e7646d2SAndroid Build Coastguard Worker 	  {
1469*5e7646d2SAndroid Build Coastguard Worker 	    (*driver)->interface = interface;
1470*5e7646d2SAndroid Build Coastguard Worker 	    (*driver)->Initialize(driver, genericDriver);
1471*5e7646d2SAndroid Build Coastguard Worker 
1472*5e7646d2SAndroid Build Coastguard Worker 	    (*driver)->plugin = plugin;
1473*5e7646d2SAndroid Build Coastguard Worker 	    (*driver)->interface = interface;
1474*5e7646d2SAndroid Build Coastguard Worker 	    *printerDriver = driver;
1475*5e7646d2SAndroid Build Coastguard Worker 	  }
1476*5e7646d2SAndroid Build Coastguard Worker 	}
1477*5e7646d2SAndroid Build Coastguard Worker 	(*iunknown)->Release(iunknown);
1478*5e7646d2SAndroid Build Coastguard Worker       }
1479*5e7646d2SAndroid Build Coastguard Worker       CFRelease(factories);
1480*5e7646d2SAndroid Build Coastguard Worker     }
1481*5e7646d2SAndroid Build Coastguard Worker   }
1482*5e7646d2SAndroid Build Coastguard Worker 
1483*5e7646d2SAndroid Build Coastguard Worker   fprintf(stderr, "DEBUG: load_classdriver(%s) (kr:0x%08x)\n", bundlestr, (int)kr);
1484*5e7646d2SAndroid Build Coastguard Worker 
1485*5e7646d2SAndroid Build Coastguard Worker   return (kr);
1486*5e7646d2SAndroid Build Coastguard Worker }
1487*5e7646d2SAndroid Build Coastguard Worker 
1488*5e7646d2SAndroid Build Coastguard Worker 
1489*5e7646d2SAndroid Build Coastguard Worker /*
1490*5e7646d2SAndroid Build Coastguard Worker  * 'unload_classdriver()' - Unload a classdriver.
1491*5e7646d2SAndroid Build Coastguard Worker  */
1492*5e7646d2SAndroid Build Coastguard Worker 
unload_classdriver(classdriver_t *** classdriver)1493*5e7646d2SAndroid Build Coastguard Worker static kern_return_t unload_classdriver(classdriver_t ***classdriver)
1494*5e7646d2SAndroid Build Coastguard Worker {
1495*5e7646d2SAndroid Build Coastguard Worker   if (*classdriver != NULL)
1496*5e7646d2SAndroid Build Coastguard Worker   {
1497*5e7646d2SAndroid Build Coastguard Worker     (**classdriver)->Release(*classdriver);
1498*5e7646d2SAndroid Build Coastguard Worker     *classdriver = NULL;
1499*5e7646d2SAndroid Build Coastguard Worker   }
1500*5e7646d2SAndroid Build Coastguard Worker 
1501*5e7646d2SAndroid Build Coastguard Worker   return kIOReturnSuccess;
1502*5e7646d2SAndroid Build Coastguard Worker }
1503*5e7646d2SAndroid Build Coastguard Worker 
1504*5e7646d2SAndroid Build Coastguard Worker 
1505*5e7646d2SAndroid Build Coastguard Worker /*
1506*5e7646d2SAndroid Build Coastguard Worker  * 'load_printerdriver()' - Load vendor's classdriver.
1507*5e7646d2SAndroid Build Coastguard Worker  *
1508*5e7646d2SAndroid Build Coastguard Worker  * If driverBundlePath is not NULL on return it is the callers responsbility to release it!
1509*5e7646d2SAndroid Build Coastguard Worker  */
1510*5e7646d2SAndroid Build Coastguard Worker 
load_printerdriver(CFStringRef * driverBundlePath)1511*5e7646d2SAndroid Build Coastguard Worker static kern_return_t load_printerdriver(CFStringRef *driverBundlePath)
1512*5e7646d2SAndroid Build Coastguard Worker {
1513*5e7646d2SAndroid Build Coastguard Worker   IOCFPlugInInterface	**iodev = NULL;
1514*5e7646d2SAndroid Build Coastguard Worker   SInt32		score;
1515*5e7646d2SAndroid Build Coastguard Worker   kern_return_t		kr;
1516*5e7646d2SAndroid Build Coastguard Worker   printer_interface_t	interface;
1517*5e7646d2SAndroid Build Coastguard Worker 
1518*5e7646d2SAndroid Build Coastguard Worker   kr = IOCreatePlugInInterfaceForService(g.printer_obj, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
1519*5e7646d2SAndroid Build Coastguard Worker   if (kr == kIOReturnSuccess)
1520*5e7646d2SAndroid Build Coastguard Worker   {
1521*5e7646d2SAndroid Build Coastguard Worker     if ((*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &interface) == noErr)
1522*5e7646d2SAndroid Build Coastguard Worker     {
1523*5e7646d2SAndroid Build Coastguard Worker       *driverBundlePath = IORegistryEntryCreateCFProperty(g.printer_obj, kUSBClassDriverProperty, NULL, kNilOptions);
1524*5e7646d2SAndroid Build Coastguard Worker 
1525*5e7646d2SAndroid Build Coastguard Worker       g.use_generic_class_driver = (*driverBundlePath == NULL || (CFStringCompare(*driverBundlePath, kUSBGenericTOPrinterClassDriver, 0x0) == kCFCompareEqualTo));
1526*5e7646d2SAndroid Build Coastguard Worker       kr = load_classdriver(*driverBundlePath, interface, &g.classdriver);
1527*5e7646d2SAndroid Build Coastguard Worker 
1528*5e7646d2SAndroid Build Coastguard Worker       if (kr != kIOReturnSuccess)
1529*5e7646d2SAndroid Build Coastguard Worker 	(*interface)->Release(interface);
1530*5e7646d2SAndroid Build Coastguard Worker     }
1531*5e7646d2SAndroid Build Coastguard Worker     IODestroyPlugInInterface(iodev);
1532*5e7646d2SAndroid Build Coastguard Worker   }
1533*5e7646d2SAndroid Build Coastguard Worker   return kr;
1534*5e7646d2SAndroid Build Coastguard Worker }
1535*5e7646d2SAndroid Build Coastguard Worker 
usb_printer_interface_interface(io_service_t usbClass)1536*5e7646d2SAndroid Build Coastguard Worker static printer_interface_t usb_printer_interface_interface(io_service_t usbClass)
1537*5e7646d2SAndroid Build Coastguard Worker {
1538*5e7646d2SAndroid Build Coastguard Worker 	printer_interface_t  intf = NULL;
1539*5e7646d2SAndroid Build Coastguard Worker 	IOCFPlugInInterface **plugin = NULL;
1540*5e7646d2SAndroid Build Coastguard Worker 	SInt32	score;
1541*5e7646d2SAndroid Build Coastguard Worker 	int kr = IOCreatePlugInInterfaceForService(usbClass, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score);
1542*5e7646d2SAndroid Build Coastguard Worker 	if (kr == kIOReturnSuccess)
1543*5e7646d2SAndroid Build Coastguard Worker 	{
1544*5e7646d2SAndroid Build Coastguard Worker 		(*plugin)->QueryInterface(plugin, USB_INTERFACE_KIND, (LPVOID *)&intf);
1545*5e7646d2SAndroid Build Coastguard Worker 		IODestroyPlugInInterface(plugin);
1546*5e7646d2SAndroid Build Coastguard Worker 	}
1547*5e7646d2SAndroid Build Coastguard Worker 
1548*5e7646d2SAndroid Build Coastguard Worker 	return intf;
1549*5e7646d2SAndroid Build Coastguard Worker }
1550*5e7646d2SAndroid Build Coastguard Worker 
copy_printer_interface_deviceid(printer_interface_t printer,UInt8 alternateSetting)1551*5e7646d2SAndroid Build Coastguard Worker static CFStringRef copy_printer_interface_deviceid(printer_interface_t printer, UInt8 alternateSetting)
1552*5e7646d2SAndroid Build Coastguard Worker {
1553*5e7646d2SAndroid Build Coastguard Worker 	// I have tried to make this function as neat as I can, but the possibility of needing to resend
1554*5e7646d2SAndroid Build Coastguard Worker 	// a request to get the entire string makes it hideous...
1555*5e7646d2SAndroid Build Coastguard Worker 	//
1556*5e7646d2SAndroid Build Coastguard Worker 	// We package the job of sending a request up into the block (^sendRequest), which takes the size
1557*5e7646d2SAndroid Build Coastguard Worker 	// it should allocate for the message buffer. It frees the current buffer if one is set and
1558*5e7646d2SAndroid Build Coastguard Worker 	// allocates one of the specified size, then performs the request. We can then easily retry by
1559*5e7646d2SAndroid Build Coastguard Worker 	// calling the block again if we fail to get the whole string the first time around.
1560*5e7646d2SAndroid Build Coastguard Worker 
1561*5e7646d2SAndroid Build Coastguard Worker 	#define kUSBPrintClassGetDeviceID           0
1562*5e7646d2SAndroid Build Coastguard Worker 	#define kDefaultNoDataTimeout               5000L
1563*5e7646d2SAndroid Build Coastguard Worker 	#define pack_device_id_wIndex(intf, alt)  ((UInt16)((((UInt16)(intf)) << 8) | ((UInt8)(alt))))
1564*5e7646d2SAndroid Build Coastguard Worker 
1565*5e7646d2SAndroid Build Coastguard Worker 	if (printer == NULL)
1566*5e7646d2SAndroid Build Coastguard Worker 			return NULL;
1567*5e7646d2SAndroid Build Coastguard Worker 
1568*5e7646d2SAndroid Build Coastguard Worker 
1569*5e7646d2SAndroid Build Coastguard Worker 	IOReturn err        = kIOReturnError;
1570*5e7646d2SAndroid Build Coastguard Worker 	UInt8    configurationIndex	= 0;
1571*5e7646d2SAndroid Build Coastguard Worker 	UInt8    interfaceNumber	= 0;
1572*5e7646d2SAndroid Build Coastguard Worker 	size_t   bufferLength		= 256;
1573*5e7646d2SAndroid Build Coastguard Worker 	CFStringRef ret             = NULL;
1574*5e7646d2SAndroid Build Coastguard Worker 
1575*5e7646d2SAndroid Build Coastguard Worker 	if ((*printer)->GetConfigurationValue( printer, &configurationIndex) == kIOReturnSuccess &&
1576*5e7646d2SAndroid Build Coastguard Worker 			(*printer)->GetInterfaceNumber( printer, &interfaceNumber) == kIOReturnSuccess)
1577*5e7646d2SAndroid Build Coastguard Worker 	{
1578*5e7646d2SAndroid Build Coastguard Worker 		__block IOUSBDevRequestTO	request;
1579*5e7646d2SAndroid Build Coastguard Worker 		IOReturn (^sendRequest)(size_t) = ^ (size_t size)
1580*5e7646d2SAndroid Build Coastguard Worker 		{
1581*5e7646d2SAndroid Build Coastguard Worker 			if (request.pData)
1582*5e7646d2SAndroid Build Coastguard Worker 			{
1583*5e7646d2SAndroid Build Coastguard Worker 				free(request.pData);
1584*5e7646d2SAndroid Build Coastguard Worker 				request.wLength = 0;
1585*5e7646d2SAndroid Build Coastguard Worker 				request.pData = NULL;
1586*5e7646d2SAndroid Build Coastguard Worker 			}
1587*5e7646d2SAndroid Build Coastguard Worker 
1588*5e7646d2SAndroid Build Coastguard Worker 			IOReturn berr = kIOReturnError;
1589*5e7646d2SAndroid Build Coastguard Worker 			char *buffer = malloc(size);
1590*5e7646d2SAndroid Build Coastguard Worker 			if (buffer == NULL)
1591*5e7646d2SAndroid Build Coastguard Worker 				return kIOReturnNoMemory;
1592*5e7646d2SAndroid Build Coastguard Worker 
1593*5e7646d2SAndroid Build Coastguard Worker 			request.wLength = HostToUSBWord(size);
1594*5e7646d2SAndroid Build Coastguard Worker 			request.pData = buffer;
1595*5e7646d2SAndroid Build Coastguard Worker 			berr = (*printer)->ControlRequestTO(printer, (UInt8)0, &request);
1596*5e7646d2SAndroid Build Coastguard Worker 			return berr;
1597*5e7646d2SAndroid Build Coastguard Worker 		};
1598*5e7646d2SAndroid Build Coastguard Worker 
1599*5e7646d2SAndroid Build Coastguard Worker 		/* This request takes the 0 based configuration index. IOKit returns a 1 based configuration index */
1600*5e7646d2SAndroid Build Coastguard Worker 		configurationIndex -= 1;
1601*5e7646d2SAndroid Build Coastguard Worker 
1602*5e7646d2SAndroid Build Coastguard Worker 		memset(&request, 0, sizeof(request));
1603*5e7646d2SAndroid Build Coastguard Worker 
1604*5e7646d2SAndroid Build Coastguard Worker 		request.bmRequestType		= USBmakebmRequestType(kUSBIn, kUSBClass, kUSBInterface);
1605*5e7646d2SAndroid Build Coastguard Worker 		request.bRequest			= kUSBPrintClassGetDeviceID;
1606*5e7646d2SAndroid Build Coastguard Worker 		request.wValue				= HostToUSBWord(configurationIndex);
1607*5e7646d2SAndroid Build Coastguard Worker 		request.wIndex				= HostToUSBWord(pack_device_id_wIndex(interfaceNumber, alternateSetting));
1608*5e7646d2SAndroid Build Coastguard Worker 		request.noDataTimeout		= kDefaultNoDataTimeout;
1609*5e7646d2SAndroid Build Coastguard Worker 		request.completionTimeout	= 0; // Copying behavior from Generic Class Driver
1610*5e7646d2SAndroid Build Coastguard Worker 
1611*5e7646d2SAndroid Build Coastguard Worker 		err = sendRequest(bufferLength);
1612*5e7646d2SAndroid Build Coastguard Worker 
1613*5e7646d2SAndroid Build Coastguard Worker 		if (err == kIOReturnSuccess && request.wLenDone > 1)
1614*5e7646d2SAndroid Build Coastguard Worker 		{
1615*5e7646d2SAndroid Build Coastguard Worker 			UInt16 actualLength = OSSwapBigToHostInt16(*((UInt16 *)request.pData));
1616*5e7646d2SAndroid Build Coastguard Worker 
1617*5e7646d2SAndroid Build Coastguard Worker 			if (actualLength > 2 && actualLength <= bufferLength - 2)
1618*5e7646d2SAndroid Build Coastguard Worker 			{
1619*5e7646d2SAndroid Build Coastguard Worker 				ret = CFStringCreateWithBytes(NULL, (const UInt8 *)request.pData + 2, actualLength - 2, kCFStringEncodingUTF8, false);
1620*5e7646d2SAndroid Build Coastguard Worker 			}
1621*5e7646d2SAndroid Build Coastguard Worker 			else if (actualLength > 2) {
1622*5e7646d2SAndroid Build Coastguard Worker 				err = sendRequest(actualLength);
1623*5e7646d2SAndroid Build Coastguard Worker 				if (err == kIOReturnSuccess && request.wLenDone > 0)
1624*5e7646d2SAndroid Build Coastguard Worker 				{
1625*5e7646d2SAndroid Build Coastguard Worker 					actualLength = OSSwapBigToHostInt16(*((UInt16 *)request.pData));
1626*5e7646d2SAndroid Build Coastguard Worker 					ret = CFStringCreateWithBytes(NULL, (const UInt8 *)request.pData + 2, actualLength - 2, kCFStringEncodingUTF8, false);
1627*5e7646d2SAndroid Build Coastguard Worker 				}
1628*5e7646d2SAndroid Build Coastguard Worker 			}
1629*5e7646d2SAndroid Build Coastguard Worker 		}
1630*5e7646d2SAndroid Build Coastguard Worker 
1631*5e7646d2SAndroid Build Coastguard Worker 		if (request.pData)
1632*5e7646d2SAndroid Build Coastguard Worker 			free(request.pData);
1633*5e7646d2SAndroid Build Coastguard Worker 	}
1634*5e7646d2SAndroid Build Coastguard Worker 
1635*5e7646d2SAndroid Build Coastguard Worker 	CFStringRef manufacturer = deviceIDCopyManufacturer(ret);
1636*5e7646d2SAndroid Build Coastguard Worker 	CFStringRef model = deviceIDCopyModel(ret);
1637*5e7646d2SAndroid Build Coastguard Worker 	CFStringRef serial = deviceIDCopySerialNumber(ret);
1638*5e7646d2SAndroid Build Coastguard Worker 
1639*5e7646d2SAndroid Build Coastguard Worker 	if (manufacturer == NULL || serial == NULL || model == NULL)
1640*5e7646d2SAndroid Build Coastguard Worker 	{
1641*5e7646d2SAndroid Build Coastguard Worker 		IOUSBDevRequestTO		request;
1642*5e7646d2SAndroid Build Coastguard Worker 		IOUSBDeviceDescriptor	desc;
1643*5e7646d2SAndroid Build Coastguard Worker 
1644*5e7646d2SAndroid Build Coastguard Worker 		memset(&request, 0, sizeof(request));
1645*5e7646d2SAndroid Build Coastguard Worker 
1646*5e7646d2SAndroid Build Coastguard Worker 		request.bmRequestType = USBmakebmRequestType( kUSBIn,  kUSBStandard, kUSBDevice );
1647*5e7646d2SAndroid Build Coastguard Worker 		request.bRequest = kUSBRqGetDescriptor;
1648*5e7646d2SAndroid Build Coastguard Worker 		request.wValue = kUSBDeviceDesc << 8;
1649*5e7646d2SAndroid Build Coastguard Worker 		request.wIndex = 0;
1650*5e7646d2SAndroid Build Coastguard Worker 		request.wLength = sizeof(desc);
1651*5e7646d2SAndroid Build Coastguard Worker 		request.pData = &desc;
1652*5e7646d2SAndroid Build Coastguard Worker 		request.completionTimeout = 0;
1653*5e7646d2SAndroid Build Coastguard Worker 		request.noDataTimeout = 60L;
1654*5e7646d2SAndroid Build Coastguard Worker 
1655*5e7646d2SAndroid Build Coastguard Worker 		err = (*printer)->ControlRequestTO(printer, 0, &request);
1656*5e7646d2SAndroid Build Coastguard Worker 		if (err == kIOReturnSuccess)
1657*5e7646d2SAndroid Build Coastguard Worker 		{
1658*5e7646d2SAndroid Build Coastguard Worker 			CFMutableStringRef extras = CFStringCreateMutable(NULL, 0);
1659*5e7646d2SAndroid Build Coastguard Worker 			if (manufacturer == NULL)
1660*5e7646d2SAndroid Build Coastguard Worker 			{
1661*5e7646d2SAndroid Build Coastguard Worker 				manufacturer = copy_printer_interface_indexed_description(printer, desc.iManufacturer, kUSBLanguageEnglish);
1662*5e7646d2SAndroid Build Coastguard Worker 				if (manufacturer && CFStringGetLength(manufacturer) > 0)
1663*5e7646d2SAndroid Build Coastguard Worker 					CFStringAppendFormat(extras, NULL, CFSTR("MFG:%@;"), manufacturer);
1664*5e7646d2SAndroid Build Coastguard Worker 			}
1665*5e7646d2SAndroid Build Coastguard Worker 
1666*5e7646d2SAndroid Build Coastguard Worker 			if (model == NULL)
1667*5e7646d2SAndroid Build Coastguard Worker 			{
1668*5e7646d2SAndroid Build Coastguard Worker 				model = copy_printer_interface_indexed_description(printer, desc.iProduct, kUSBLanguageEnglish);
1669*5e7646d2SAndroid Build Coastguard Worker 				if (model && CFStringGetLength(model) > 0)
1670*5e7646d2SAndroid Build Coastguard Worker 					CFStringAppendFormat(extras, NULL, CFSTR("MDL:%@;"), model);
1671*5e7646d2SAndroid Build Coastguard Worker 			}
1672*5e7646d2SAndroid Build Coastguard Worker 
1673*5e7646d2SAndroid Build Coastguard Worker 			if (desc.iSerialNumber != 0)
1674*5e7646d2SAndroid Build Coastguard Worker 			{
1675*5e7646d2SAndroid Build Coastguard Worker 				// Always look at the USB serial number since some printers
1676*5e7646d2SAndroid Build Coastguard Worker 				// incorrectly include a bogus static serial number in their
1677*5e7646d2SAndroid Build Coastguard Worker 				// IEEE-1284 device ID string...
1678*5e7646d2SAndroid Build Coastguard Worker 				CFStringRef userial = copy_printer_interface_indexed_description(printer, desc.iSerialNumber, kUSBLanguageEnglish);
1679*5e7646d2SAndroid Build Coastguard Worker 				if (userial && CFStringGetLength(userial) > 0 && (serial == NULL || CFStringCompare(serial, userial, kCFCompareCaseInsensitive) != kCFCompareEqualTo))
1680*5e7646d2SAndroid Build Coastguard Worker 				{
1681*5e7646d2SAndroid Build Coastguard Worker 					if (serial != NULL)
1682*5e7646d2SAndroid Build Coastguard Worker 					{
1683*5e7646d2SAndroid Build Coastguard Worker 						// 1284 serial number doesn't match USB serial number, so  replace the existing SERN: in device ID
1684*5e7646d2SAndroid Build Coastguard Worker 						CFRange range = CFStringFind(ret, serial, 0);
1685*5e7646d2SAndroid Build Coastguard Worker 						CFMutableStringRef deviceIDString = CFStringCreateMutableCopy(NULL, 0, ret);
1686*5e7646d2SAndroid Build Coastguard Worker 						CFStringReplace(deviceIDString, range, userial);
1687*5e7646d2SAndroid Build Coastguard Worker 						CFRelease(ret);
1688*5e7646d2SAndroid Build Coastguard Worker 						ret = deviceIDString;
1689*5e7646d2SAndroid Build Coastguard Worker 
1690*5e7646d2SAndroid Build Coastguard Worker 						CFRelease(serial);
1691*5e7646d2SAndroid Build Coastguard Worker 					}
1692*5e7646d2SAndroid Build Coastguard Worker 					else
1693*5e7646d2SAndroid Build Coastguard Worker 					{
1694*5e7646d2SAndroid Build Coastguard Worker 						// No 1284 serial number so add SERN: with USB serial number to device ID
1695*5e7646d2SAndroid Build Coastguard Worker 						CFStringAppendFormat(extras, NULL, CFSTR("SERN:%@;"), userial);
1696*5e7646d2SAndroid Build Coastguard Worker 					}
1697*5e7646d2SAndroid Build Coastguard Worker 					serial = userial;
1698*5e7646d2SAndroid Build Coastguard Worker 				}
1699*5e7646d2SAndroid Build Coastguard Worker 				else if (userial != NULL)
1700*5e7646d2SAndroid Build Coastguard Worker 					CFRelease(userial);
1701*5e7646d2SAndroid Build Coastguard Worker 			}
1702*5e7646d2SAndroid Build Coastguard Worker 
1703*5e7646d2SAndroid Build Coastguard Worker 			if (ret != NULL)
1704*5e7646d2SAndroid Build Coastguard Worker 			{
1705*5e7646d2SAndroid Build Coastguard Worker 				CFStringAppend(extras, ret);
1706*5e7646d2SAndroid Build Coastguard Worker 				CFRelease(ret);
1707*5e7646d2SAndroid Build Coastguard Worker 			}
1708*5e7646d2SAndroid Build Coastguard Worker       ret = extras;
1709*5e7646d2SAndroid Build Coastguard Worker 		}
1710*5e7646d2SAndroid Build Coastguard Worker 	}
1711*5e7646d2SAndroid Build Coastguard Worker 
1712*5e7646d2SAndroid Build Coastguard Worker 	if (ret != NULL)
1713*5e7646d2SAndroid Build Coastguard Worker 	{
1714*5e7646d2SAndroid Build Coastguard Worker 		/* Remove special characters from the serial number */
1715*5e7646d2SAndroid Build Coastguard Worker 		CFRange range = (serial != NULL ? CFStringFind(serial, CFSTR("+"), 0) : CFRangeMake(0, 0));
1716*5e7646d2SAndroid Build Coastguard Worker 		if (range.length == 1)
1717*5e7646d2SAndroid Build Coastguard Worker 		{
1718*5e7646d2SAndroid Build Coastguard Worker 			range = CFStringFind(ret, serial, 0);
1719*5e7646d2SAndroid Build Coastguard Worker 
1720*5e7646d2SAndroid Build Coastguard Worker 			CFMutableStringRef deviceIDString = CFStringCreateMutableCopy(NULL, 0, ret);
1721*5e7646d2SAndroid Build Coastguard Worker 			CFRelease(ret);
1722*5e7646d2SAndroid Build Coastguard Worker 
1723*5e7646d2SAndroid Build Coastguard Worker 			ret = deviceIDString;
1724*5e7646d2SAndroid Build Coastguard Worker 			CFStringFindAndReplace(deviceIDString, CFSTR("+"), CFSTR(""), range, 0);
1725*5e7646d2SAndroid Build Coastguard Worker 		}
1726*5e7646d2SAndroid Build Coastguard Worker 	}
1727*5e7646d2SAndroid Build Coastguard Worker 
1728*5e7646d2SAndroid Build Coastguard Worker 	if (manufacturer != NULL)
1729*5e7646d2SAndroid Build Coastguard Worker 		CFRelease(manufacturer);
1730*5e7646d2SAndroid Build Coastguard Worker 
1731*5e7646d2SAndroid Build Coastguard Worker 	if (model != NULL)
1732*5e7646d2SAndroid Build Coastguard Worker 		CFRelease(model);
1733*5e7646d2SAndroid Build Coastguard Worker 
1734*5e7646d2SAndroid Build Coastguard Worker 	if (serial != NULL)
1735*5e7646d2SAndroid Build Coastguard Worker 		CFRelease(serial);
1736*5e7646d2SAndroid Build Coastguard Worker 
1737*5e7646d2SAndroid Build Coastguard Worker 	if (ret != NULL && CFStringGetLength(ret) == 0)
1738*5e7646d2SAndroid Build Coastguard Worker 	{
1739*5e7646d2SAndroid Build Coastguard Worker 		CFRelease(ret);
1740*5e7646d2SAndroid Build Coastguard Worker 		return NULL;
1741*5e7646d2SAndroid Build Coastguard Worker 	}
1742*5e7646d2SAndroid Build Coastguard Worker 
1743*5e7646d2SAndroid Build Coastguard Worker 	return ret;
1744*5e7646d2SAndroid Build Coastguard Worker }
1745*5e7646d2SAndroid Build Coastguard Worker 
copy_printer_interface_indexed_description(printer_interface_t printer,UInt8 index,UInt16 language)1746*5e7646d2SAndroid Build Coastguard Worker static CFStringRef copy_printer_interface_indexed_description(printer_interface_t  printer, UInt8 index, UInt16 language)
1747*5e7646d2SAndroid Build Coastguard Worker {
1748*5e7646d2SAndroid Build Coastguard Worker 	IOReturn err;
1749*5e7646d2SAndroid Build Coastguard Worker 	UInt8 description[256]; // Max possible descriptor length
1750*5e7646d2SAndroid Build Coastguard Worker 	IOUSBDevRequestTO	request;
1751*5e7646d2SAndroid Build Coastguard Worker 
1752*5e7646d2SAndroid Build Coastguard Worker 	memset(description, 0, 2);
1753*5e7646d2SAndroid Build Coastguard Worker 
1754*5e7646d2SAndroid Build Coastguard Worker 	request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
1755*5e7646d2SAndroid Build Coastguard Worker 	request.bRequest = kUSBRqGetDescriptor;
1756*5e7646d2SAndroid Build Coastguard Worker 	request.wValue = (kUSBStringDesc << 8) | index;
1757*5e7646d2SAndroid Build Coastguard Worker 	request.wIndex = language;
1758*5e7646d2SAndroid Build Coastguard Worker 	request.wLength = 2;
1759*5e7646d2SAndroid Build Coastguard Worker 	request.pData = &description;
1760*5e7646d2SAndroid Build Coastguard Worker 	request.completionTimeout = 0;
1761*5e7646d2SAndroid Build Coastguard Worker 	request.noDataTimeout = 60L;
1762*5e7646d2SAndroid Build Coastguard Worker 
1763*5e7646d2SAndroid Build Coastguard Worker 	err = (*printer)->ControlRequestTO(printer, 0, &request);
1764*5e7646d2SAndroid Build Coastguard Worker 	if (err != kIOReturnSuccess && err != kIOReturnOverrun)
1765*5e7646d2SAndroid Build Coastguard Worker 	{
1766*5e7646d2SAndroid Build Coastguard Worker 		memset(description, 0, request.wLength);
1767*5e7646d2SAndroid Build Coastguard Worker 
1768*5e7646d2SAndroid Build Coastguard Worker 		// Let's try again full length. Here's why:
1769*5e7646d2SAndroid Build Coastguard Worker 		//      On USB 2.0 controllers, we will not get an overrun error.  We just get a "babble" error
1770*5e7646d2SAndroid Build Coastguard Worker 		//      and no valid data.  So, if we ask for the max size, we will either get it, or we'll get an underrun.
1771*5e7646d2SAndroid Build Coastguard Worker 		//      It looks like we get it w/out an underrun
1772*5e7646d2SAndroid Build Coastguard Worker 
1773*5e7646d2SAndroid Build Coastguard Worker 		request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
1774*5e7646d2SAndroid Build Coastguard Worker 		request.bRequest = kUSBRqGetDescriptor;
1775*5e7646d2SAndroid Build Coastguard Worker 		request.wValue = (kUSBStringDesc << 8) | index;
1776*5e7646d2SAndroid Build Coastguard Worker 		request.wIndex = language;
1777*5e7646d2SAndroid Build Coastguard Worker 		request.wLength = sizeof description;
1778*5e7646d2SAndroid Build Coastguard Worker 		request.pData = &description;
1779*5e7646d2SAndroid Build Coastguard Worker 		request.completionTimeout = 0;
1780*5e7646d2SAndroid Build Coastguard Worker 		request.noDataTimeout = 60L;
1781*5e7646d2SAndroid Build Coastguard Worker 
1782*5e7646d2SAndroid Build Coastguard Worker 		err = (*printer)->ControlRequestTO(printer, 0, &request);
1783*5e7646d2SAndroid Build Coastguard Worker 		if (err != kIOReturnSuccess && err != kIOReturnUnderrun)
1784*5e7646d2SAndroid Build Coastguard Worker 			return NULL;
1785*5e7646d2SAndroid Build Coastguard Worker 	}
1786*5e7646d2SAndroid Build Coastguard Worker 
1787*5e7646d2SAndroid Build Coastguard Worker 	unsigned int length = description[0];
1788*5e7646d2SAndroid Build Coastguard Worker 	if (length == 0)
1789*5e7646d2SAndroid Build Coastguard Worker 		return CFStringCreateWithCString(NULL, "", kCFStringEncodingUTF8);
1790*5e7646d2SAndroid Build Coastguard Worker 
1791*5e7646d2SAndroid Build Coastguard Worker 	if (description[1] != kUSBStringDesc)
1792*5e7646d2SAndroid Build Coastguard Worker 		return NULL;
1793*5e7646d2SAndroid Build Coastguard Worker 
1794*5e7646d2SAndroid Build Coastguard Worker 	request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
1795*5e7646d2SAndroid Build Coastguard Worker 	request.bRequest = kUSBRqGetDescriptor;
1796*5e7646d2SAndroid Build Coastguard Worker 	request.wValue = (kUSBStringDesc << 8) | index;
1797*5e7646d2SAndroid Build Coastguard Worker 	request.wIndex = language;
1798*5e7646d2SAndroid Build Coastguard Worker 
1799*5e7646d2SAndroid Build Coastguard Worker 	memset(description, 0, length);
1800*5e7646d2SAndroid Build Coastguard Worker 	request.wLength = (UInt16)length;
1801*5e7646d2SAndroid Build Coastguard Worker 	request.pData = &description;
1802*5e7646d2SAndroid Build Coastguard Worker 	request.completionTimeout = 0;
1803*5e7646d2SAndroid Build Coastguard Worker 	request.noDataTimeout = 60L;
1804*5e7646d2SAndroid Build Coastguard Worker 
1805*5e7646d2SAndroid Build Coastguard Worker 	err = (*printer)->ControlRequestTO(printer, 0, &request);
1806*5e7646d2SAndroid Build Coastguard Worker 	if (err != kIOReturnSuccess)
1807*5e7646d2SAndroid Build Coastguard Worker 		return NULL;
1808*5e7646d2SAndroid Build Coastguard Worker 
1809*5e7646d2SAndroid Build Coastguard Worker 	if (description[1] != kUSBStringDesc)
1810*5e7646d2SAndroid Build Coastguard Worker 		return NULL;
1811*5e7646d2SAndroid Build Coastguard Worker 
1812*5e7646d2SAndroid Build Coastguard Worker 	if ((description[0] & 1) != 0)
1813*5e7646d2SAndroid Build Coastguard Worker 		description[0] &= 0xfe;
1814*5e7646d2SAndroid Build Coastguard Worker 
1815*5e7646d2SAndroid Build Coastguard Worker 	char buffer[258] = {0};
1816*5e7646d2SAndroid Build Coastguard Worker 	unsigned int maxLength = sizeof buffer;
1817*5e7646d2SAndroid Build Coastguard Worker 	if (description[0] > 1)
1818*5e7646d2SAndroid Build Coastguard Worker 	{
1819*5e7646d2SAndroid Build Coastguard Worker 		length = (description[0]-2)/2;
1820*5e7646d2SAndroid Build Coastguard Worker 
1821*5e7646d2SAndroid Build Coastguard Worker 		if (length > maxLength - 1)
1822*5e7646d2SAndroid Build Coastguard Worker 			length = maxLength -1;
1823*5e7646d2SAndroid Build Coastguard Worker 
1824*5e7646d2SAndroid Build Coastguard Worker 		for (unsigned i = 0; i < length; i++)
1825*5e7646d2SAndroid Build Coastguard Worker 			buffer[i] = (char) description[2*i+2];
1826*5e7646d2SAndroid Build Coastguard Worker 
1827*5e7646d2SAndroid Build Coastguard Worker 		buffer[length] = 0;
1828*5e7646d2SAndroid Build Coastguard Worker 	}
1829*5e7646d2SAndroid Build Coastguard Worker 
1830*5e7646d2SAndroid Build Coastguard Worker 	return CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
1831*5e7646d2SAndroid Build Coastguard Worker }
1832*5e7646d2SAndroid Build Coastguard Worker 
1833*5e7646d2SAndroid Build Coastguard Worker /*
1834*5e7646d2SAndroid Build Coastguard Worker  * 'registry_open()' - Open a connection to the printer.
1835*5e7646d2SAndroid Build Coastguard Worker  */
1836*5e7646d2SAndroid Build Coastguard Worker 
registry_open(CFStringRef * driverBundlePath)1837*5e7646d2SAndroid Build Coastguard Worker static kern_return_t registry_open(CFStringRef *driverBundlePath)
1838*5e7646d2SAndroid Build Coastguard Worker {
1839*5e7646d2SAndroid Build Coastguard Worker   g.bidi_flag = 0;	/* 0=unidirectional */
1840*5e7646d2SAndroid Build Coastguard Worker 
1841*5e7646d2SAndroid Build Coastguard Worker   kern_return_t kr = load_printerdriver(driverBundlePath);
1842*5e7646d2SAndroid Build Coastguard Worker   if (kr != kIOReturnSuccess)
1843*5e7646d2SAndroid Build Coastguard Worker     kr = -2;
1844*5e7646d2SAndroid Build Coastguard Worker 
1845*5e7646d2SAndroid Build Coastguard Worker   if (g.classdriver != NULL)
1846*5e7646d2SAndroid Build Coastguard Worker   {
1847*5e7646d2SAndroid Build Coastguard Worker   	(*g.classdriver)->interfaceNumber = g.interfaceNum;
1848*5e7646d2SAndroid Build Coastguard Worker     kr = (*g.classdriver)->Open(g.classdriver, g.location, kUSBPrintingProtocolBidirectional);
1849*5e7646d2SAndroid Build Coastguard Worker     if (kr != kIOReturnSuccess || (*g.classdriver)->interface == NULL)
1850*5e7646d2SAndroid Build Coastguard Worker     {
1851*5e7646d2SAndroid Build Coastguard Worker       kr = (*g.classdriver)->Open(g.classdriver, g.location, kUSBPrintingProtocolUnidirectional);
1852*5e7646d2SAndroid Build Coastguard Worker       if (kr == kIOReturnSuccess)
1853*5e7646d2SAndroid Build Coastguard Worker       {
1854*5e7646d2SAndroid Build Coastguard Worker 	if ((*g.classdriver)->interface == NULL)
1855*5e7646d2SAndroid Build Coastguard Worker 	{
1856*5e7646d2SAndroid Build Coastguard Worker 	  (*g.classdriver)->Close(g.classdriver);
1857*5e7646d2SAndroid Build Coastguard Worker 	  kr = -1;
1858*5e7646d2SAndroid Build Coastguard Worker 	}
1859*5e7646d2SAndroid Build Coastguard Worker       }
1860*5e7646d2SAndroid Build Coastguard Worker     }
1861*5e7646d2SAndroid Build Coastguard Worker     else
1862*5e7646d2SAndroid Build Coastguard Worker       g.bidi_flag = 1;	/* 1=bidirectional */
1863*5e7646d2SAndroid Build Coastguard Worker   }
1864*5e7646d2SAndroid Build Coastguard Worker 
1865*5e7646d2SAndroid Build Coastguard Worker   if (kr != kIOReturnSuccess)
1866*5e7646d2SAndroid Build Coastguard Worker     unload_classdriver(&g.classdriver);
1867*5e7646d2SAndroid Build Coastguard Worker 
1868*5e7646d2SAndroid Build Coastguard Worker   return kr;
1869*5e7646d2SAndroid Build Coastguard Worker }
1870*5e7646d2SAndroid Build Coastguard Worker 
1871*5e7646d2SAndroid Build Coastguard Worker 
1872*5e7646d2SAndroid Build Coastguard Worker /*
1873*5e7646d2SAndroid Build Coastguard Worker  * 'registry_close()' - Close the connection to the printer.
1874*5e7646d2SAndroid Build Coastguard Worker  */
1875*5e7646d2SAndroid Build Coastguard Worker 
registry_close(void)1876*5e7646d2SAndroid Build Coastguard Worker static kern_return_t registry_close(void)
1877*5e7646d2SAndroid Build Coastguard Worker {
1878*5e7646d2SAndroid Build Coastguard Worker   if (g.classdriver != NULL)
1879*5e7646d2SAndroid Build Coastguard Worker     (*g.classdriver)->Close(g.classdriver);
1880*5e7646d2SAndroid Build Coastguard Worker 
1881*5e7646d2SAndroid Build Coastguard Worker   unload_classdriver(&g.classdriver);
1882*5e7646d2SAndroid Build Coastguard Worker   return kIOReturnSuccess;
1883*5e7646d2SAndroid Build Coastguard Worker }
1884*5e7646d2SAndroid Build Coastguard Worker 
1885*5e7646d2SAndroid Build Coastguard Worker #pragma mark -
1886*5e7646d2SAndroid Build Coastguard Worker /*
1887*5e7646d2SAndroid Build Coastguard Worker  * 'copy_value_for_key()' - Copy value string associated with a key.
1888*5e7646d2SAndroid Build Coastguard Worker  */
1889*5e7646d2SAndroid Build Coastguard Worker 
copy_value_for_key(CFStringRef deviceID,CFStringRef * keys)1890*5e7646d2SAndroid Build Coastguard Worker static CFStringRef copy_value_for_key(CFStringRef deviceID,
1891*5e7646d2SAndroid Build Coastguard Worker 				      CFStringRef *keys)
1892*5e7646d2SAndroid Build Coastguard Worker {
1893*5e7646d2SAndroid Build Coastguard Worker   CFStringRef	value = NULL;
1894*5e7646d2SAndroid Build Coastguard Worker   CFArrayRef	kvPairs = deviceID != NULL ? CFStringCreateArrayBySeparatingStrings(NULL, deviceID, CFSTR(";")) : NULL;
1895*5e7646d2SAndroid Build Coastguard Worker   CFIndex	max = kvPairs != NULL ? CFArrayGetCount(kvPairs) : 0;
1896*5e7646d2SAndroid Build Coastguard Worker   CFIndex	idx = 0;
1897*5e7646d2SAndroid Build Coastguard Worker 
1898*5e7646d2SAndroid Build Coastguard Worker   while (idx < max && value == NULL)
1899*5e7646d2SAndroid Build Coastguard Worker   {
1900*5e7646d2SAndroid Build Coastguard Worker     CFStringRef kvpair = CFArrayGetValueAtIndex(kvPairs, idx);
1901*5e7646d2SAndroid Build Coastguard Worker     CFIndex idxx = 0;
1902*5e7646d2SAndroid Build Coastguard Worker     while (keys[idxx] != NULL && value == NULL)
1903*5e7646d2SAndroid Build Coastguard Worker     {
1904*5e7646d2SAndroid Build Coastguard Worker       CFRange range = CFStringFind(kvpair, keys[idxx], kCFCompareCaseInsensitive);
1905*5e7646d2SAndroid Build Coastguard Worker       if (range.length != -1)
1906*5e7646d2SAndroid Build Coastguard Worker       {
1907*5e7646d2SAndroid Build Coastguard Worker 	if (range.location != 0)
1908*5e7646d2SAndroid Build Coastguard Worker 	{
1909*5e7646d2SAndroid Build Coastguard Worker 	  CFMutableStringRef theString = CFStringCreateMutableCopy(NULL, 0, kvpair);
1910*5e7646d2SAndroid Build Coastguard Worker 	  CFStringTrimWhitespace(theString);
1911*5e7646d2SAndroid Build Coastguard Worker 	  range = CFStringFind(theString, keys[idxx], kCFCompareCaseInsensitive);
1912*5e7646d2SAndroid Build Coastguard Worker 	  if (range.location == 0)
1913*5e7646d2SAndroid Build Coastguard Worker 	    value = CFStringCreateWithSubstring(NULL, theString, CFRangeMake(range.length, CFStringGetLength(theString) - range.length));
1914*5e7646d2SAndroid Build Coastguard Worker 
1915*5e7646d2SAndroid Build Coastguard Worker 	  CFRelease(theString);
1916*5e7646d2SAndroid Build Coastguard Worker 	}
1917*5e7646d2SAndroid Build Coastguard Worker 	else
1918*5e7646d2SAndroid Build Coastguard Worker 	{
1919*5e7646d2SAndroid Build Coastguard Worker 	  CFStringRef theString = CFStringCreateWithSubstring(NULL, kvpair, CFRangeMake(range.length, CFStringGetLength(kvpair) - range.length));
1920*5e7646d2SAndroid Build Coastguard Worker 	  CFMutableStringRef theString2 = CFStringCreateMutableCopy(NULL, 0, theString);
1921*5e7646d2SAndroid Build Coastguard Worker 	  CFRelease(theString);
1922*5e7646d2SAndroid Build Coastguard Worker 
1923*5e7646d2SAndroid Build Coastguard Worker 	  CFStringTrimWhitespace(theString2);
1924*5e7646d2SAndroid Build Coastguard Worker 	  value = theString2;
1925*5e7646d2SAndroid Build Coastguard Worker 	}
1926*5e7646d2SAndroid Build Coastguard Worker       }
1927*5e7646d2SAndroid Build Coastguard Worker       idxx++;
1928*5e7646d2SAndroid Build Coastguard Worker     }
1929*5e7646d2SAndroid Build Coastguard Worker     idx++;
1930*5e7646d2SAndroid Build Coastguard Worker   }
1931*5e7646d2SAndroid Build Coastguard Worker 
1932*5e7646d2SAndroid Build Coastguard Worker   if (kvPairs != NULL)
1933*5e7646d2SAndroid Build Coastguard Worker     CFRelease(kvPairs);
1934*5e7646d2SAndroid Build Coastguard Worker   return value;
1935*5e7646d2SAndroid Build Coastguard Worker }
1936*5e7646d2SAndroid Build Coastguard Worker 
1937*5e7646d2SAndroid Build Coastguard Worker 
1938*5e7646d2SAndroid Build Coastguard Worker /*
1939*5e7646d2SAndroid Build Coastguard Worker  * 'cfstr_create_trim()' - Create CFString and trim whitespace characters.
1940*5e7646d2SAndroid Build Coastguard Worker  */
1941*5e7646d2SAndroid Build Coastguard Worker 
cfstr_create_trim(const char * cstr)1942*5e7646d2SAndroid Build Coastguard Worker CFStringRef cfstr_create_trim(const char *cstr)
1943*5e7646d2SAndroid Build Coastguard Worker {
1944*5e7646d2SAndroid Build Coastguard Worker   CFStringRef		cfstr;
1945*5e7646d2SAndroid Build Coastguard Worker   CFMutableStringRef	cfmutablestr = NULL;
1946*5e7646d2SAndroid Build Coastguard Worker 
1947*5e7646d2SAndroid Build Coastguard Worker   if ((cfstr = CFStringCreateWithCString(NULL, cstr, kCFStringEncodingUTF8)) != NULL)
1948*5e7646d2SAndroid Build Coastguard Worker   {
1949*5e7646d2SAndroid Build Coastguard Worker     if ((cfmutablestr = CFStringCreateMutableCopy(NULL, 1024, cfstr)) != NULL)
1950*5e7646d2SAndroid Build Coastguard Worker       CFStringTrimWhitespace(cfmutablestr);
1951*5e7646d2SAndroid Build Coastguard Worker 
1952*5e7646d2SAndroid Build Coastguard Worker     CFRelease(cfstr);
1953*5e7646d2SAndroid Build Coastguard Worker   }
1954*5e7646d2SAndroid Build Coastguard Worker   return (CFStringRef) cfmutablestr;
1955*5e7646d2SAndroid Build Coastguard Worker }
1956*5e7646d2SAndroid Build Coastguard Worker 
1957*5e7646d2SAndroid Build Coastguard Worker 
1958*5e7646d2SAndroid Build Coastguard Worker #pragma mark -
1959*5e7646d2SAndroid Build Coastguard Worker /*
1960*5e7646d2SAndroid Build Coastguard Worker  * 'parse_options()' - Parse URI options.
1961*5e7646d2SAndroid Build Coastguard Worker  */
1962*5e7646d2SAndroid Build Coastguard Worker 
parse_options(char * options,char * serial,int serial_size,UInt32 * location,Boolean * wait_eof)1963*5e7646d2SAndroid Build Coastguard Worker static void parse_options(char *options,
1964*5e7646d2SAndroid Build Coastguard Worker 			  char *serial,
1965*5e7646d2SAndroid Build Coastguard Worker 			  int serial_size,
1966*5e7646d2SAndroid Build Coastguard Worker 			  UInt32 *location,
1967*5e7646d2SAndroid Build Coastguard Worker 			  Boolean *wait_eof)
1968*5e7646d2SAndroid Build Coastguard Worker {
1969*5e7646d2SAndroid Build Coastguard Worker   char	sep,				/* Separator character */
1970*5e7646d2SAndroid Build Coastguard Worker 	*name,				/* Name of option */
1971*5e7646d2SAndroid Build Coastguard Worker 	*value;				/* Value of option */
1972*5e7646d2SAndroid Build Coastguard Worker 
1973*5e7646d2SAndroid Build Coastguard Worker 
1974*5e7646d2SAndroid Build Coastguard Worker   if (serial)
1975*5e7646d2SAndroid Build Coastguard Worker     *serial = '\0';
1976*5e7646d2SAndroid Build Coastguard Worker   if (location)
1977*5e7646d2SAndroid Build Coastguard Worker     *location = 0;
1978*5e7646d2SAndroid Build Coastguard Worker 
1979*5e7646d2SAndroid Build Coastguard Worker   if (!options)
1980*5e7646d2SAndroid Build Coastguard Worker     return;
1981*5e7646d2SAndroid Build Coastguard Worker 
1982*5e7646d2SAndroid Build Coastguard Worker   while (*options)
1983*5e7646d2SAndroid Build Coastguard Worker   {
1984*5e7646d2SAndroid Build Coastguard Worker    /*
1985*5e7646d2SAndroid Build Coastguard Worker     * Get the name...
1986*5e7646d2SAndroid Build Coastguard Worker     */
1987*5e7646d2SAndroid Build Coastguard Worker 
1988*5e7646d2SAndroid Build Coastguard Worker     name = options;
1989*5e7646d2SAndroid Build Coastguard Worker 
1990*5e7646d2SAndroid Build Coastguard Worker     while (*options && *options != '=' && *options != '+' && *options != '&')
1991*5e7646d2SAndroid Build Coastguard Worker       options ++;
1992*5e7646d2SAndroid Build Coastguard Worker 
1993*5e7646d2SAndroid Build Coastguard Worker     if ((sep = *options) != '\0')
1994*5e7646d2SAndroid Build Coastguard Worker       *options++ = '\0';
1995*5e7646d2SAndroid Build Coastguard Worker 
1996*5e7646d2SAndroid Build Coastguard Worker     if (sep == '=')
1997*5e7646d2SAndroid Build Coastguard Worker     {
1998*5e7646d2SAndroid Build Coastguard Worker      /*
1999*5e7646d2SAndroid Build Coastguard Worker       * Get the value...
2000*5e7646d2SAndroid Build Coastguard Worker       */
2001*5e7646d2SAndroid Build Coastguard Worker 
2002*5e7646d2SAndroid Build Coastguard Worker       value = options;
2003*5e7646d2SAndroid Build Coastguard Worker 
2004*5e7646d2SAndroid Build Coastguard Worker       while (*options && *options != '+' && *options != '&')
2005*5e7646d2SAndroid Build Coastguard Worker 	options ++;
2006*5e7646d2SAndroid Build Coastguard Worker 
2007*5e7646d2SAndroid Build Coastguard Worker       if (*options)
2008*5e7646d2SAndroid Build Coastguard Worker 	*options++ = '\0';
2009*5e7646d2SAndroid Build Coastguard Worker     }
2010*5e7646d2SAndroid Build Coastguard Worker     else
2011*5e7646d2SAndroid Build Coastguard Worker       value = (char *)"";
2012*5e7646d2SAndroid Build Coastguard Worker 
2013*5e7646d2SAndroid Build Coastguard Worker    /*
2014*5e7646d2SAndroid Build Coastguard Worker     * Process the option...
2015*5e7646d2SAndroid Build Coastguard Worker     */
2016*5e7646d2SAndroid Build Coastguard Worker 
2017*5e7646d2SAndroid Build Coastguard Worker     if (!_cups_strcasecmp(name, "waiteof"))
2018*5e7646d2SAndroid Build Coastguard Worker     {
2019*5e7646d2SAndroid Build Coastguard Worker       if (!_cups_strcasecmp(value, "on") ||
2020*5e7646d2SAndroid Build Coastguard Worker 	  !_cups_strcasecmp(value, "yes") ||
2021*5e7646d2SAndroid Build Coastguard Worker 	  !_cups_strcasecmp(value, "true"))
2022*5e7646d2SAndroid Build Coastguard Worker 	*wait_eof = true;
2023*5e7646d2SAndroid Build Coastguard Worker       else if (!_cups_strcasecmp(value, "off") ||
2024*5e7646d2SAndroid Build Coastguard Worker 	       !_cups_strcasecmp(value, "no") ||
2025*5e7646d2SAndroid Build Coastguard Worker 	       !_cups_strcasecmp(value, "false"))
2026*5e7646d2SAndroid Build Coastguard Worker 	*wait_eof = false;
2027*5e7646d2SAndroid Build Coastguard Worker       else
2028*5e7646d2SAndroid Build Coastguard Worker 	_cupsLangPrintFilter(stderr, "WARNING",
2029*5e7646d2SAndroid Build Coastguard Worker 			     _("Boolean expected for waiteof option \"%s\"."),
2030*5e7646d2SAndroid Build Coastguard Worker 			     value);
2031*5e7646d2SAndroid Build Coastguard Worker     }
2032*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(name, "serial"))
2033*5e7646d2SAndroid Build Coastguard Worker       strlcpy(serial, value, (size_t)serial_size);
2034*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(name, "location") && location)
2035*5e7646d2SAndroid Build Coastguard Worker       *location = (UInt32)strtoul(value, NULL, 16);
2036*5e7646d2SAndroid Build Coastguard Worker   }
2037*5e7646d2SAndroid Build Coastguard Worker }
2038*5e7646d2SAndroid Build Coastguard Worker 
2039*5e7646d2SAndroid Build Coastguard Worker 
2040*5e7646d2SAndroid Build Coastguard Worker /*!
2041*5e7646d2SAndroid Build Coastguard Worker  * @function	setup_cfLanguage
2042*5e7646d2SAndroid Build Coastguard Worker  * @abstract	Convert the contents of the CUPS 'APPLE_LANGUAGE' environment
2043*5e7646d2SAndroid Build Coastguard Worker  *		variable into a one element CF array of languages.
2044*5e7646d2SAndroid Build Coastguard Worker  *
2045*5e7646d2SAndroid Build Coastguard Worker  * @discussion	Each submitted job comes with a natural language. CUPS passes
2046*5e7646d2SAndroid Build Coastguard Worker  * 		that language in an environment variable. We take that language
2047*5e7646d2SAndroid Build Coastguard Worker  * 		and jam it into the AppleLanguages array so that CF will use
2048*5e7646d2SAndroid Build Coastguard Worker  * 		it when reading localized resources. We need to do this before
2049*5e7646d2SAndroid Build Coastguard Worker  * 		any CF code reads and caches the languages array, so this function
2050*5e7646d2SAndroid Build Coastguard Worker  *		should be called early in main()
2051*5e7646d2SAndroid Build Coastguard Worker  */
setup_cfLanguage(void)2052*5e7646d2SAndroid Build Coastguard Worker static void setup_cfLanguage(void)
2053*5e7646d2SAndroid Build Coastguard Worker {
2054*5e7646d2SAndroid Build Coastguard Worker   CFStringRef	lang[1] = {NULL};
2055*5e7646d2SAndroid Build Coastguard Worker   CFArrayRef	langArray = NULL;
2056*5e7646d2SAndroid Build Coastguard Worker   const char	*requestedLang = NULL;
2057*5e7646d2SAndroid Build Coastguard Worker 
2058*5e7646d2SAndroid Build Coastguard Worker   if ((requestedLang = getenv("APPLE_LANGUAGE")) == NULL)
2059*5e7646d2SAndroid Build Coastguard Worker     requestedLang = getenv("LANG");
2060*5e7646d2SAndroid Build Coastguard Worker 
2061*5e7646d2SAndroid Build Coastguard Worker   if (requestedLang != NULL)
2062*5e7646d2SAndroid Build Coastguard Worker   {
2063*5e7646d2SAndroid Build Coastguard Worker     lang[0] = CFStringCreateWithCString(kCFAllocatorDefault, requestedLang, kCFStringEncodingUTF8);
2064*5e7646d2SAndroid Build Coastguard Worker     langArray = CFArrayCreate(kCFAllocatorDefault, (const void **)lang, sizeof(lang) / sizeof(lang[0]), &kCFTypeArrayCallBacks);
2065*5e7646d2SAndroid Build Coastguard Worker 
2066*5e7646d2SAndroid Build Coastguard Worker     CFPreferencesSetValue(CFSTR("AppleLanguages"), langArray, kCFPreferencesCurrentApplication, kCFPreferencesAnyUser, kCFPreferencesAnyHost);
2067*5e7646d2SAndroid Build Coastguard Worker     fprintf(stderr, "DEBUG: usb: AppleLanguages=\"%s\"\n", requestedLang);
2068*5e7646d2SAndroid Build Coastguard Worker 
2069*5e7646d2SAndroid Build Coastguard Worker     CFRelease(lang[0]);
2070*5e7646d2SAndroid Build Coastguard Worker     CFRelease(langArray);
2071*5e7646d2SAndroid Build Coastguard Worker   }
2072*5e7646d2SAndroid Build Coastguard Worker   else
2073*5e7646d2SAndroid Build Coastguard Worker     fputs("DEBUG: usb: LANG and APPLE_LANGUAGE environment variables missing.\n", stderr);
2074*5e7646d2SAndroid Build Coastguard Worker }
2075*5e7646d2SAndroid Build Coastguard Worker 
2076*5e7646d2SAndroid Build Coastguard Worker #pragma mark -
2077*5e7646d2SAndroid Build Coastguard Worker #if defined(__arm64e__)
2078*5e7646d2SAndroid Build Coastguard Worker /*!
2079*5e7646d2SAndroid Build Coastguard Worker  * @function	run_legacy_backend
2080*5e7646d2SAndroid Build Coastguard Worker  *
2081*5e7646d2SAndroid Build Coastguard Worker  * @abstract	Starts child backend process running as a x86_64 executable.
2082*5e7646d2SAndroid Build Coastguard Worker  *
2083*5e7646d2SAndroid Build Coastguard Worker  * @result	Never returns; always calls exit().
2084*5e7646d2SAndroid Build Coastguard Worker  *
2085*5e7646d2SAndroid Build Coastguard Worker  * @discussion
2086*5e7646d2SAndroid Build Coastguard Worker  */
run_legacy_backend(int argc,char * argv[],int fd)2087*5e7646d2SAndroid Build Coastguard Worker static void run_legacy_backend(int argc,
2088*5e7646d2SAndroid Build Coastguard Worker 			       char *argv[],
2089*5e7646d2SAndroid Build Coastguard Worker 			       int fd)
2090*5e7646d2SAndroid Build Coastguard Worker {
2091*5e7646d2SAndroid Build Coastguard Worker   int	i;
2092*5e7646d2SAndroid Build Coastguard Worker   int	exitstatus = 0;
2093*5e7646d2SAndroid Build Coastguard Worker   int	childstatus;
2094*5e7646d2SAndroid Build Coastguard Worker   pid_t	waitpid_status;
2095*5e7646d2SAndroid Build Coastguard Worker   char	*my_argv[32];
2096*5e7646d2SAndroid Build Coastguard Worker   char	*usb_legacy_status;
2097*5e7646d2SAndroid Build Coastguard Worker 
2098*5e7646d2SAndroid Build Coastguard Worker 
2099*5e7646d2SAndroid Build Coastguard Worker  /*
2100*5e7646d2SAndroid Build Coastguard Worker   * If we're running as ARM and couldn't load the class driver
2101*5e7646d2SAndroid Build Coastguard Worker   * (because it's x86_64, i386 or ppc), then try to re-exec ourselves in x86_64
2102*5e7646d2SAndroid Build Coastguard Worker   * mode to try again. If we don't have that architecture we may be
2103*5e7646d2SAndroid Build Coastguard Worker   * running with the same architecture again so guard against this by setting
2104*5e7646d2SAndroid Build Coastguard Worker   * and testing an environment variable...
2105*5e7646d2SAndroid Build Coastguard Worker   */
2106*5e7646d2SAndroid Build Coastguard Worker 
2107*5e7646d2SAndroid Build Coastguard Worker   usb_legacy_status = getenv("USB_LEGACY_STATUS");
2108*5e7646d2SAndroid Build Coastguard Worker 
2109*5e7646d2SAndroid Build Coastguard Worker   if (!usb_legacy_status)
2110*5e7646d2SAndroid Build Coastguard Worker   {
2111*5e7646d2SAndroid Build Coastguard Worker    /*
2112*5e7646d2SAndroid Build Coastguard Worker     * Setup a SIGTERM handler then block it before forking...
2113*5e7646d2SAndroid Build Coastguard Worker     */
2114*5e7646d2SAndroid Build Coastguard Worker 
2115*5e7646d2SAndroid Build Coastguard Worker     int			err;		/* posix_spawn result */
2116*5e7646d2SAndroid Build Coastguard Worker     struct sigaction	action;		/* POSIX signal action */
2117*5e7646d2SAndroid Build Coastguard Worker     sigset_t		newmask,	/* New signal mask */
2118*5e7646d2SAndroid Build Coastguard Worker 			oldmask;	/* Old signal mask */
2119*5e7646d2SAndroid Build Coastguard Worker     char		usbpath[1024];	/* Path to USB backend */
2120*5e7646d2SAndroid Build Coastguard Worker     const char		*cups_serverbin;/* Path to CUPS binaries */
2121*5e7646d2SAndroid Build Coastguard Worker 
2122*5e7646d2SAndroid Build Coastguard Worker 
2123*5e7646d2SAndroid Build Coastguard Worker     memset(&action, 0, sizeof(action));
2124*5e7646d2SAndroid Build Coastguard Worker     sigaddset(&action.sa_mask, SIGTERM);
2125*5e7646d2SAndroid Build Coastguard Worker     action.sa_handler = sigterm_handler;
2126*5e7646d2SAndroid Build Coastguard Worker     sigaction(SIGTERM, &action, NULL);
2127*5e7646d2SAndroid Build Coastguard Worker 
2128*5e7646d2SAndroid Build Coastguard Worker     sigemptyset(&newmask);
2129*5e7646d2SAndroid Build Coastguard Worker     sigaddset(&newmask, SIGTERM);
2130*5e7646d2SAndroid Build Coastguard Worker     sigprocmask(SIG_BLOCK, &newmask, &oldmask);
2131*5e7646d2SAndroid Build Coastguard Worker 
2132*5e7646d2SAndroid Build Coastguard Worker    /*
2133*5e7646d2SAndroid Build Coastguard Worker     * Set the environment variable...
2134*5e7646d2SAndroid Build Coastguard Worker     */
2135*5e7646d2SAndroid Build Coastguard Worker 
2136*5e7646d2SAndroid Build Coastguard Worker     setenv("USB_LEGACY_STATUS", "1", false);
2137*5e7646d2SAndroid Build Coastguard Worker 
2138*5e7646d2SAndroid Build Coastguard Worker    /*
2139*5e7646d2SAndroid Build Coastguard Worker     * Tell the kernel to use the specified CPU architecture...
2140*5e7646d2SAndroid Build Coastguard Worker     */
2141*5e7646d2SAndroid Build Coastguard Worker 
2142*5e7646d2SAndroid Build Coastguard Worker     cpu_type_t cpu = CPU_TYPE_X86_64;
2143*5e7646d2SAndroid Build Coastguard Worker     size_t ocount = 1;
2144*5e7646d2SAndroid Build Coastguard Worker     posix_spawnattr_t attrs;
2145*5e7646d2SAndroid Build Coastguard Worker 
2146*5e7646d2SAndroid Build Coastguard Worker     if (!posix_spawnattr_init(&attrs))
2147*5e7646d2SAndroid Build Coastguard Worker     {
2148*5e7646d2SAndroid Build Coastguard Worker       posix_spawnattr_setsigdefault(&attrs, &oldmask);
2149*5e7646d2SAndroid Build Coastguard Worker       if (posix_spawnattr_setbinpref_np(&attrs, 1, &cpu, &ocount) || ocount != 1)
2150*5e7646d2SAndroid Build Coastguard Worker       {
2151*5e7646d2SAndroid Build Coastguard Worker 	perror("DEBUG: Unable to set binary preference to X86_64");
2152*5e7646d2SAndroid Build Coastguard Worker 	_cupsLangPrintFilter(stderr, "ERROR",
2153*5e7646d2SAndroid Build Coastguard Worker 	                     _("Unable to use legacy USB class driver."));
2154*5e7646d2SAndroid Build Coastguard Worker 	exit(CUPS_BACKEND_STOP);
2155*5e7646d2SAndroid Build Coastguard Worker       }
2156*5e7646d2SAndroid Build Coastguard Worker     }
2157*5e7646d2SAndroid Build Coastguard Worker 
2158*5e7646d2SAndroid Build Coastguard Worker    /*
2159*5e7646d2SAndroid Build Coastguard Worker     * Set up the arguments and call posix_spawn...
2160*5e7646d2SAndroid Build Coastguard Worker     */
2161*5e7646d2SAndroid Build Coastguard Worker 
2162*5e7646d2SAndroid Build Coastguard Worker     if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
2163*5e7646d2SAndroid Build Coastguard Worker       cups_serverbin = CUPS_SERVERBIN;
2164*5e7646d2SAndroid Build Coastguard Worker     snprintf(usbpath, sizeof(usbpath), "%s/backend/usb", cups_serverbin);
2165*5e7646d2SAndroid Build Coastguard Worker 
2166*5e7646d2SAndroid Build Coastguard Worker     for (i = 0; i < argc && i < (int)(sizeof(my_argv) / sizeof(my_argv[0])) - 1; i ++)
2167*5e7646d2SAndroid Build Coastguard Worker       my_argv[i] = argv[i];
2168*5e7646d2SAndroid Build Coastguard Worker 
2169*5e7646d2SAndroid Build Coastguard Worker     my_argv[i] = NULL;
2170*5e7646d2SAndroid Build Coastguard Worker 
2171*5e7646d2SAndroid Build Coastguard Worker     if ((err = posix_spawn(&child_pid, usbpath, NULL, &attrs, my_argv,
2172*5e7646d2SAndroid Build Coastguard Worker                            environ)) != 0)
2173*5e7646d2SAndroid Build Coastguard Worker     {
2174*5e7646d2SAndroid Build Coastguard Worker       fprintf(stderr, "DEBUG: Unable to exec %s: %s\n", usbpath,
2175*5e7646d2SAndroid Build Coastguard Worker               strerror(err));
2176*5e7646d2SAndroid Build Coastguard Worker       _cupsLangPrintFilter(stderr, "ERROR",
2177*5e7646d2SAndroid Build Coastguard Worker                            _("Unable to use legacy USB class driver."));
2178*5e7646d2SAndroid Build Coastguard Worker       exit(CUPS_BACKEND_STOP);
2179*5e7646d2SAndroid Build Coastguard Worker     }
2180*5e7646d2SAndroid Build Coastguard Worker 
2181*5e7646d2SAndroid Build Coastguard Worker    /*
2182*5e7646d2SAndroid Build Coastguard Worker     * Unblock signals...
2183*5e7646d2SAndroid Build Coastguard Worker     */
2184*5e7646d2SAndroid Build Coastguard Worker 
2185*5e7646d2SAndroid Build Coastguard Worker     sigprocmask(SIG_SETMASK, &oldmask, NULL);
2186*5e7646d2SAndroid Build Coastguard Worker 
2187*5e7646d2SAndroid Build Coastguard Worker    /*
2188*5e7646d2SAndroid Build Coastguard Worker     * Close the fds we won't be using then wait for the child backend to exit.
2189*5e7646d2SAndroid Build Coastguard Worker     */
2190*5e7646d2SAndroid Build Coastguard Worker 
2191*5e7646d2SAndroid Build Coastguard Worker     close(fd);
2192*5e7646d2SAndroid Build Coastguard Worker     close(1);
2193*5e7646d2SAndroid Build Coastguard Worker 
2194*5e7646d2SAndroid Build Coastguard Worker     fprintf(stderr, "DEBUG: Started usb(legacy) backend (PID %d)\n",
2195*5e7646d2SAndroid Build Coastguard Worker             (int)child_pid);
2196*5e7646d2SAndroid Build Coastguard Worker 
2197*5e7646d2SAndroid Build Coastguard Worker     while ((waitpid_status = waitpid(child_pid, &childstatus, 0)) == (pid_t)-1 && errno == EINTR)
2198*5e7646d2SAndroid Build Coastguard Worker       usleep(1000);
2199*5e7646d2SAndroid Build Coastguard Worker 
2200*5e7646d2SAndroid Build Coastguard Worker     if (WIFSIGNALED(childstatus))
2201*5e7646d2SAndroid Build Coastguard Worker     {
2202*5e7646d2SAndroid Build Coastguard Worker       exitstatus = CUPS_BACKEND_STOP;
2203*5e7646d2SAndroid Build Coastguard Worker       fprintf(stderr, "DEBUG: usb(legacy) backend %d crashed on signal %d\n",
2204*5e7646d2SAndroid Build Coastguard Worker               child_pid, WTERMSIG(childstatus));
2205*5e7646d2SAndroid Build Coastguard Worker     }
2206*5e7646d2SAndroid Build Coastguard Worker     else
2207*5e7646d2SAndroid Build Coastguard Worker     {
2208*5e7646d2SAndroid Build Coastguard Worker       if ((exitstatus = WEXITSTATUS(childstatus)) != 0)
2209*5e7646d2SAndroid Build Coastguard Worker 	fprintf(stderr,
2210*5e7646d2SAndroid Build Coastguard Worker 	        "DEBUG: usb(legacy) backend %d stopped with status %d\n",
2211*5e7646d2SAndroid Build Coastguard Worker 		child_pid, exitstatus);
2212*5e7646d2SAndroid Build Coastguard Worker       else
2213*5e7646d2SAndroid Build Coastguard Worker 	fprintf(stderr, "DEBUG: usb(legacy) backend %d exited with no errors\n",
2214*5e7646d2SAndroid Build Coastguard Worker 	        child_pid);
2215*5e7646d2SAndroid Build Coastguard Worker     }
2216*5e7646d2SAndroid Build Coastguard Worker   }
2217*5e7646d2SAndroid Build Coastguard Worker   else
2218*5e7646d2SAndroid Build Coastguard Worker   {
2219*5e7646d2SAndroid Build Coastguard Worker     fputs("DEBUG: usb(legacy) backend running native again\n", stderr);
2220*5e7646d2SAndroid Build Coastguard Worker     exitstatus = CUPS_BACKEND_STOP;
2221*5e7646d2SAndroid Build Coastguard Worker   }
2222*5e7646d2SAndroid Build Coastguard Worker 
2223*5e7646d2SAndroid Build Coastguard Worker   exit(exitstatus);
2224*5e7646d2SAndroid Build Coastguard Worker }
2225*5e7646d2SAndroid Build Coastguard Worker 
2226*5e7646d2SAndroid Build Coastguard Worker /*
2227*5e7646d2SAndroid Build Coastguard Worker  * 'sigterm_handler()' - SIGTERM handler.
2228*5e7646d2SAndroid Build Coastguard Worker  */
2229*5e7646d2SAndroid Build Coastguard Worker 
2230*5e7646d2SAndroid Build Coastguard Worker static void
sigterm_handler(int sig)2231*5e7646d2SAndroid Build Coastguard Worker sigterm_handler(int sig)		/* I - Signal */
2232*5e7646d2SAndroid Build Coastguard Worker {
2233*5e7646d2SAndroid Build Coastguard Worker  /*
2234*5e7646d2SAndroid Build Coastguard Worker   * If we started a child process pass the signal on to it...
2235*5e7646d2SAndroid Build Coastguard Worker   */
2236*5e7646d2SAndroid Build Coastguard Worker 
2237*5e7646d2SAndroid Build Coastguard Worker   if (child_pid)
2238*5e7646d2SAndroid Build Coastguard Worker   {
2239*5e7646d2SAndroid Build Coastguard Worker    /*
2240*5e7646d2SAndroid Build Coastguard Worker     * If we started a child process pass the signal on to it...
2241*5e7646d2SAndroid Build Coastguard Worker     */
2242*5e7646d2SAndroid Build Coastguard Worker 
2243*5e7646d2SAndroid Build Coastguard Worker     int	status;
2244*5e7646d2SAndroid Build Coastguard Worker 
2245*5e7646d2SAndroid Build Coastguard Worker     kill(child_pid, sig);
2246*5e7646d2SAndroid Build Coastguard Worker     while (waitpid(child_pid, &status, 0) < 0 && errno == EINTR);
2247*5e7646d2SAndroid Build Coastguard Worker 
2248*5e7646d2SAndroid Build Coastguard Worker     if (WIFEXITED(status))
2249*5e7646d2SAndroid Build Coastguard Worker       _exit(WEXITSTATUS(status));
2250*5e7646d2SAndroid Build Coastguard Worker     else if (status == SIGTERM || status == SIGKILL)
2251*5e7646d2SAndroid Build Coastguard Worker       _exit(0);
2252*5e7646d2SAndroid Build Coastguard Worker     else
2253*5e7646d2SAndroid Build Coastguard Worker     {
2254*5e7646d2SAndroid Build Coastguard Worker       backendMessage("DEBUG: Child crashed.\n");
2255*5e7646d2SAndroid Build Coastguard Worker       _exit(CUPS_BACKEND_STOP);
2256*5e7646d2SAndroid Build Coastguard Worker     }
2257*5e7646d2SAndroid Build Coastguard Worker   }
2258*5e7646d2SAndroid Build Coastguard Worker }
2259*5e7646d2SAndroid Build Coastguard Worker #endif /* __arm64e__ */
2260*5e7646d2SAndroid Build Coastguard Worker 
2261*5e7646d2SAndroid Build Coastguard Worker 
2262*5e7646d2SAndroid Build Coastguard Worker /*
2263*5e7646d2SAndroid Build Coastguard Worker  * 'sigquit_handler()' - SIGQUIT handler.
2264*5e7646d2SAndroid Build Coastguard Worker  */
2265*5e7646d2SAndroid Build Coastguard Worker 
sigquit_handler(int sig,siginfo_t * si,void * unused)2266*5e7646d2SAndroid Build Coastguard Worker static void sigquit_handler(int sig, siginfo_t *si, void *unused)
2267*5e7646d2SAndroid Build Coastguard Worker {
2268*5e7646d2SAndroid Build Coastguard Worker   char  *path;
2269*5e7646d2SAndroid Build Coastguard Worker   char	pathbuf[PROC_PIDPATHINFO_MAXSIZE];
2270*5e7646d2SAndroid Build Coastguard Worker   static char msgbuf[256] = "";
2271*5e7646d2SAndroid Build Coastguard Worker 
2272*5e7646d2SAndroid Build Coastguard Worker 
2273*5e7646d2SAndroid Build Coastguard Worker   (void)sig;
2274*5e7646d2SAndroid Build Coastguard Worker   (void)unused;
2275*5e7646d2SAndroid Build Coastguard Worker 
2276*5e7646d2SAndroid Build Coastguard Worker   if (proc_pidpath(si->si_pid, pathbuf, sizeof(pathbuf)) > 0 &&
2277*5e7646d2SAndroid Build Coastguard Worker       (path = basename(pathbuf)) != NULL)
2278*5e7646d2SAndroid Build Coastguard Worker     snprintf(msgbuf, sizeof(msgbuf), "SIGQUIT sent by %s(%d)", path, (int)si->si_pid);
2279*5e7646d2SAndroid Build Coastguard Worker   else
2280*5e7646d2SAndroid Build Coastguard Worker     snprintf(msgbuf, sizeof(msgbuf), "SIGQUIT sent by PID %d", (int)si->si_pid);
2281*5e7646d2SAndroid Build Coastguard Worker 
2282*5e7646d2SAndroid Build Coastguard Worker   CRSetCrashLogMessage(msgbuf);
2283*5e7646d2SAndroid Build Coastguard Worker 
2284*5e7646d2SAndroid Build Coastguard Worker   abort();
2285*5e7646d2SAndroid Build Coastguard Worker }
2286*5e7646d2SAndroid Build Coastguard Worker 
2287*5e7646d2SAndroid Build Coastguard Worker 
2288*5e7646d2SAndroid Build Coastguard Worker #ifdef PARSE_PS_ERRORS
2289*5e7646d2SAndroid Build Coastguard Worker /*
2290*5e7646d2SAndroid Build Coastguard Worker  * 'next_line()' - Find the next line in a buffer.
2291*5e7646d2SAndroid Build Coastguard Worker  */
2292*5e7646d2SAndroid Build Coastguard Worker 
next_line(const char * buffer)2293*5e7646d2SAndroid Build Coastguard Worker static const char *next_line (const char *buffer)
2294*5e7646d2SAndroid Build Coastguard Worker {
2295*5e7646d2SAndroid Build Coastguard Worker   const char *cptr, *lptr = NULL;
2296*5e7646d2SAndroid Build Coastguard Worker 
2297*5e7646d2SAndroid Build Coastguard Worker   for (cptr = buffer; *cptr && lptr == NULL; cptr++)
2298*5e7646d2SAndroid Build Coastguard Worker     if (*cptr == '\n' || *cptr == '\r')
2299*5e7646d2SAndroid Build Coastguard Worker       lptr = cptr;
2300*5e7646d2SAndroid Build Coastguard Worker   return lptr;
2301*5e7646d2SAndroid Build Coastguard Worker }
2302*5e7646d2SAndroid Build Coastguard Worker 
2303*5e7646d2SAndroid Build Coastguard Worker 
2304*5e7646d2SAndroid Build Coastguard Worker /*
2305*5e7646d2SAndroid Build Coastguard Worker  * 'parse_pserror()' - Scan the backchannel data for postscript errors.
2306*5e7646d2SAndroid Build Coastguard Worker  */
2307*5e7646d2SAndroid Build Coastguard Worker 
parse_pserror(char * sockBuffer,int len)2308*5e7646d2SAndroid Build Coastguard Worker static void parse_pserror(char *sockBuffer,
2309*5e7646d2SAndroid Build Coastguard Worker 			  int len)
2310*5e7646d2SAndroid Build Coastguard Worker {
2311*5e7646d2SAndroid Build Coastguard Worker   static char  gErrorBuffer[1024] = "";
2312*5e7646d2SAndroid Build Coastguard Worker   static char *gErrorBufferPtr = gErrorBuffer;
2313*5e7646d2SAndroid Build Coastguard Worker   static char *gErrorBufferEndPtr = gErrorBuffer + sizeof(gErrorBuffer);
2314*5e7646d2SAndroid Build Coastguard Worker 
2315*5e7646d2SAndroid Build Coastguard Worker   char *pCommentBegin, *pCommentEnd, *pLineEnd;
2316*5e7646d2SAndroid Build Coastguard Worker   char *logLevel;
2317*5e7646d2SAndroid Build Coastguard Worker   char logstr[1024];
2318*5e7646d2SAndroid Build Coastguard Worker   int  logstrlen;
2319*5e7646d2SAndroid Build Coastguard Worker 
2320*5e7646d2SAndroid Build Coastguard Worker   if (gErrorBufferPtr + len > gErrorBufferEndPtr - 1)
2321*5e7646d2SAndroid Build Coastguard Worker     gErrorBufferPtr = gErrorBuffer;
2322*5e7646d2SAndroid Build Coastguard Worker   if (len > sizeof(gErrorBuffer) - 1)
2323*5e7646d2SAndroid Build Coastguard Worker     len = sizeof(gErrorBuffer) - 1;
2324*5e7646d2SAndroid Build Coastguard Worker 
2325*5e7646d2SAndroid Build Coastguard Worker   memcpy(gErrorBufferPtr, (const void *)sockBuffer, len);
2326*5e7646d2SAndroid Build Coastguard Worker   gErrorBufferPtr += len;
2327*5e7646d2SAndroid Build Coastguard Worker   *(gErrorBufferPtr + 1) = '\0';
2328*5e7646d2SAndroid Build Coastguard Worker 
2329*5e7646d2SAndroid Build Coastguard Worker   pLineEnd = (char *)next_line((const char *)gErrorBuffer);
2330*5e7646d2SAndroid Build Coastguard Worker   while (pLineEnd != NULL)
2331*5e7646d2SAndroid Build Coastguard Worker   {
2332*5e7646d2SAndroid Build Coastguard Worker     *pLineEnd++ = '\0';
2333*5e7646d2SAndroid Build Coastguard Worker 
2334*5e7646d2SAndroid Build Coastguard Worker     pCommentBegin = strstr(gErrorBuffer,"%%[");
2335*5e7646d2SAndroid Build Coastguard Worker     pCommentEnd = strstr(gErrorBuffer, "]%%");
2336*5e7646d2SAndroid Build Coastguard Worker     if (pCommentBegin != gErrorBuffer && pCommentEnd != NULL)
2337*5e7646d2SAndroid Build Coastguard Worker     {
2338*5e7646d2SAndroid Build Coastguard Worker       pCommentEnd += 3;            /* Skip past "]%%" */
2339*5e7646d2SAndroid Build Coastguard Worker       *pCommentEnd = '\0';         /* There's always room for the nul */
2340*5e7646d2SAndroid Build Coastguard Worker 
2341*5e7646d2SAndroid Build Coastguard Worker       if (_cups_strncasecmp(pCommentBegin, "%%[ Error:", 10) == 0)
2342*5e7646d2SAndroid Build Coastguard Worker 	logLevel = "DEBUG";
2343*5e7646d2SAndroid Build Coastguard Worker       else if (_cups_strncasecmp(pCommentBegin, "%%[ Flushing", 12) == 0)
2344*5e7646d2SAndroid Build Coastguard Worker 	logLevel = "DEBUG";
2345*5e7646d2SAndroid Build Coastguard Worker       else
2346*5e7646d2SAndroid Build Coastguard Worker 	logLevel = "INFO";
2347*5e7646d2SAndroid Build Coastguard Worker 
2348*5e7646d2SAndroid Build Coastguard Worker       if ((logstrlen = snprintf(logstr, sizeof(logstr), "%s: %s\n", logLevel, pCommentBegin)) >= sizeof(logstr))
2349*5e7646d2SAndroid Build Coastguard Worker       {
2350*5e7646d2SAndroid Build Coastguard Worker 	/* If the string was trucnated make sure it has a linefeed before the nul */
2351*5e7646d2SAndroid Build Coastguard Worker 	logstrlen = sizeof(logstr) - 1;
2352*5e7646d2SAndroid Build Coastguard Worker 	logstr[logstrlen - 1] = '\n';
2353*5e7646d2SAndroid Build Coastguard Worker       }
2354*5e7646d2SAndroid Build Coastguard Worker       write(STDERR_FILENO, logstr, logstrlen);
2355*5e7646d2SAndroid Build Coastguard Worker     }
2356*5e7646d2SAndroid Build Coastguard Worker 
2357*5e7646d2SAndroid Build Coastguard Worker     /* move everything over... */
2358*5e7646d2SAndroid Build Coastguard Worker     strlcpy(gErrorBuffer, pLineEnd, sizeof(gErrorBuffer));
2359*5e7646d2SAndroid Build Coastguard Worker     gErrorBufferPtr = gErrorBuffer;
2360*5e7646d2SAndroid Build Coastguard Worker     pLineEnd = (char *)next_line((const char *)gErrorBuffer);
2361*5e7646d2SAndroid Build Coastguard Worker   }
2362*5e7646d2SAndroid Build Coastguard Worker }
2363*5e7646d2SAndroid Build Coastguard Worker #endif /* PARSE_PS_ERRORS */
2364*5e7646d2SAndroid Build Coastguard Worker 
2365*5e7646d2SAndroid Build Coastguard Worker 
2366*5e7646d2SAndroid Build Coastguard Worker /*
2367*5e7646d2SAndroid Build Coastguard Worker  * 'soft_reset()' - Send a soft reset to the device.
2368*5e7646d2SAndroid Build Coastguard Worker  */
2369*5e7646d2SAndroid Build Coastguard Worker 
soft_reset(void)2370*5e7646d2SAndroid Build Coastguard Worker static void soft_reset(void)
2371*5e7646d2SAndroid Build Coastguard Worker {
2372*5e7646d2SAndroid Build Coastguard Worker   fd_set	  input_set;		/* Input set for select() */
2373*5e7646d2SAndroid Build Coastguard Worker   struct timeval  tv;			/* Time value */
2374*5e7646d2SAndroid Build Coastguard Worker   char		  buffer[2048];		/* Buffer */
2375*5e7646d2SAndroid Build Coastguard Worker   struct timespec cond_timeout;		/* pthread condition timeout */
2376*5e7646d2SAndroid Build Coastguard Worker 
2377*5e7646d2SAndroid Build Coastguard Worker  /*
2378*5e7646d2SAndroid Build Coastguard Worker   * Send an abort once a second until the I/O lock is released by the main thread...
2379*5e7646d2SAndroid Build Coastguard Worker   */
2380*5e7646d2SAndroid Build Coastguard Worker 
2381*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_lock(&g.readwrite_lock_mutex);
2382*5e7646d2SAndroid Build Coastguard Worker   while (g.readwrite_lock)
2383*5e7646d2SAndroid Build Coastguard Worker   {
2384*5e7646d2SAndroid Build Coastguard Worker     (*g.classdriver)->Abort(g.classdriver);
2385*5e7646d2SAndroid Build Coastguard Worker 
2386*5e7646d2SAndroid Build Coastguard Worker     gettimeofday(&tv, NULL);
2387*5e7646d2SAndroid Build Coastguard Worker     cond_timeout.tv_sec  = tv.tv_sec + 1;
2388*5e7646d2SAndroid Build Coastguard Worker     cond_timeout.tv_nsec = tv.tv_usec * 1000;
2389*5e7646d2SAndroid Build Coastguard Worker 
2390*5e7646d2SAndroid Build Coastguard Worker     while (g.readwrite_lock)
2391*5e7646d2SAndroid Build Coastguard Worker     {
2392*5e7646d2SAndroid Build Coastguard Worker       if (pthread_cond_timedwait(&g.readwrite_lock_cond,
2393*5e7646d2SAndroid Build Coastguard Worker 				 &g.readwrite_lock_mutex,
2394*5e7646d2SAndroid Build Coastguard Worker 				 &cond_timeout) != 0)
2395*5e7646d2SAndroid Build Coastguard Worker 	break;
2396*5e7646d2SAndroid Build Coastguard Worker     }
2397*5e7646d2SAndroid Build Coastguard Worker   }
2398*5e7646d2SAndroid Build Coastguard Worker 
2399*5e7646d2SAndroid Build Coastguard Worker   g.readwrite_lock = 1;
2400*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_unlock(&g.readwrite_lock_mutex);
2401*5e7646d2SAndroid Build Coastguard Worker 
2402*5e7646d2SAndroid Build Coastguard Worker  /*
2403*5e7646d2SAndroid Build Coastguard Worker   * Flush bytes waiting on print_fd...
2404*5e7646d2SAndroid Build Coastguard Worker   */
2405*5e7646d2SAndroid Build Coastguard Worker 
2406*5e7646d2SAndroid Build Coastguard Worker   g.print_bytes = 0;
2407*5e7646d2SAndroid Build Coastguard Worker 
2408*5e7646d2SAndroid Build Coastguard Worker   FD_ZERO(&input_set);
2409*5e7646d2SAndroid Build Coastguard Worker   FD_SET(g.print_fd, &input_set);
2410*5e7646d2SAndroid Build Coastguard Worker 
2411*5e7646d2SAndroid Build Coastguard Worker   tv.tv_sec  = 0;
2412*5e7646d2SAndroid Build Coastguard Worker   tv.tv_usec = 0;
2413*5e7646d2SAndroid Build Coastguard Worker 
2414*5e7646d2SAndroid Build Coastguard Worker   while (select(g.print_fd+1, &input_set, NULL, NULL, &tv) > 0)
2415*5e7646d2SAndroid Build Coastguard Worker     if (read(g.print_fd, buffer, sizeof(buffer)) <= 0)
2416*5e7646d2SAndroid Build Coastguard Worker       break;
2417*5e7646d2SAndroid Build Coastguard Worker 
2418*5e7646d2SAndroid Build Coastguard Worker  /*
2419*5e7646d2SAndroid Build Coastguard Worker   * Send the reset...
2420*5e7646d2SAndroid Build Coastguard Worker   */
2421*5e7646d2SAndroid Build Coastguard Worker 
2422*5e7646d2SAndroid Build Coastguard Worker   (*g.classdriver)->SoftReset(g.classdriver, DEFAULT_TIMEOUT);
2423*5e7646d2SAndroid Build Coastguard Worker 
2424*5e7646d2SAndroid Build Coastguard Worker  /*
2425*5e7646d2SAndroid Build Coastguard Worker   * Release the I/O lock...
2426*5e7646d2SAndroid Build Coastguard Worker   */
2427*5e7646d2SAndroid Build Coastguard Worker 
2428*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_lock(&g.readwrite_lock_mutex);
2429*5e7646d2SAndroid Build Coastguard Worker   g.readwrite_lock = 0;
2430*5e7646d2SAndroid Build Coastguard Worker   pthread_cond_signal(&g.readwrite_lock_cond);
2431*5e7646d2SAndroid Build Coastguard Worker   pthread_mutex_unlock(&g.readwrite_lock_mutex);
2432*5e7646d2SAndroid Build Coastguard Worker }
2433*5e7646d2SAndroid Build Coastguard Worker 
2434*5e7646d2SAndroid Build Coastguard Worker 
2435*5e7646d2SAndroid Build Coastguard Worker /*
2436*5e7646d2SAndroid Build Coastguard Worker  * 'get_device_id()' - Return IEEE-1284 device ID.
2437*5e7646d2SAndroid Build Coastguard Worker  */
2438*5e7646d2SAndroid Build Coastguard Worker 
get_device_id(cups_sc_status_t * status,char * data,int * datalen)2439*5e7646d2SAndroid Build Coastguard Worker static void get_device_id(cups_sc_status_t *status,
2440*5e7646d2SAndroid Build Coastguard Worker 			  char *data,
2441*5e7646d2SAndroid Build Coastguard Worker 			  int *datalen)
2442*5e7646d2SAndroid Build Coastguard Worker {
2443*5e7646d2SAndroid Build Coastguard Worker   CFStringRef deviceIDString = NULL;
2444*5e7646d2SAndroid Build Coastguard Worker 
2445*5e7646d2SAndroid Build Coastguard Worker   if (g.printer_obj != IO_OBJECT_NULL)
2446*5e7646d2SAndroid Build Coastguard Worker   {
2447*5e7646d2SAndroid Build Coastguard Worker     printer_interface_t printerIntf = usb_printer_interface_interface(g.printer_obj);
2448*5e7646d2SAndroid Build Coastguard Worker     if (printerIntf)
2449*5e7646d2SAndroid Build Coastguard Worker     {
2450*5e7646d2SAndroid Build Coastguard Worker       deviceIDString = copy_printer_interface_deviceid(printerIntf, g.alternateSetting);
2451*5e7646d2SAndroid Build Coastguard Worker       (*printerIntf)->Release(printerIntf);
2452*5e7646d2SAndroid Build Coastguard Worker     }
2453*5e7646d2SAndroid Build Coastguard Worker   }
2454*5e7646d2SAndroid Build Coastguard Worker 
2455*5e7646d2SAndroid Build Coastguard Worker 
2456*5e7646d2SAndroid Build Coastguard Worker   if (deviceIDString)
2457*5e7646d2SAndroid Build Coastguard Worker   {
2458*5e7646d2SAndroid Build Coastguard Worker     if (CFStringGetCString(deviceIDString, data, *datalen, kCFStringEncodingUTF8))
2459*5e7646d2SAndroid Build Coastguard Worker       *datalen = (int)strlen(data);
2460*5e7646d2SAndroid Build Coastguard Worker     else
2461*5e7646d2SAndroid Build Coastguard Worker       *datalen = 0;
2462*5e7646d2SAndroid Build Coastguard Worker 
2463*5e7646d2SAndroid Build Coastguard Worker     CFRelease(deviceIDString);
2464*5e7646d2SAndroid Build Coastguard Worker   }
2465*5e7646d2SAndroid Build Coastguard Worker   else
2466*5e7646d2SAndroid Build Coastguard Worker   {
2467*5e7646d2SAndroid Build Coastguard Worker     *datalen = 0;
2468*5e7646d2SAndroid Build Coastguard Worker   }
2469*5e7646d2SAndroid Build Coastguard Worker 
2470*5e7646d2SAndroid Build Coastguard Worker   *status  = CUPS_SC_STATUS_OK;
2471*5e7646d2SAndroid Build Coastguard Worker }
2472