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