]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/usb-darwin.c
Load cups into easysw/current.
[thirdparty/cups.git] / backend / usb-darwin.c
1 /*
2 * "$Id: usb-darwin.c 5373 2006-04-06 20:03:32Z mike $"
3 *
4 * © Copyright 2005-2006 Apple Computer, Inc. All rights reserved.
5 *
6 * IMPORTANT: This Apple software is supplied to you by Apple Computer,
7 * Inc. ("Apple") in consideration of your agreement to the following
8 * terms, and your use, installation, modification or redistribution of
9 * this Apple software constitutes acceptance of these terms. If you do
10 * not agree with these terms, please do not use, install, modify or
11 * redistribute this Apple software.
12 *
13 * In consideration of your agreement to abide by the following terms, and
14 * subject to these terms, Apple grants you a personal, non-exclusive
15 * license, under Apple's copyrights in this original Apple software (the
16 * "Apple Software"), to use, reproduce, modify and redistribute the Apple
17 * Software, with or without modifications, in source and/or binary forms;
18 * provided that if you redistribute the Apple Software in its entirety and
19 * without modifications, you must retain this notice and the following
20 * text and disclaimers in all such redistributions of the Apple Software.
21 * Neither the name, trademarks, service marks or logos of Apple Computer,
22 * Inc. may be used to endorse or promote products derived from the Apple
23 * Software without specific prior written permission from Apple. Except
24 * as expressly stated in this notice, no other rights or licenses, express
25 * or implied, are granted by Apple herein, including but not limited to
26 * any patent rights that may be infringed by your derivative works or by
27 * other works in which the Apple Software may be incorporated.
28 *
29 * The Apple Software is provided by Apple on an "AS IS" basis. APPLE
30 * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
31 * THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
32 * FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
33 * OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
34 *
35 * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
36 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 * INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
39 * MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
40 * AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
41 * STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
42 * POSSIBILITY OF SUCH DAMAGE.
43 */
44
45 /*
46 * USB port on Darwin backend for the Common UNIX Printing System (CUPS).
47 */
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <errno.h>
51 #include <signal.h>
52 #include <fcntl.h>
53 #include <termios.h>
54 #include <unistd.h>
55 #include <sys/sysctl.h>
56 #include <libgen.h>
57 #include <mach/mach.h>
58 #include <mach/mach_error.h>
59 #include <mach/mach_time.h>
60 #include <cups/debug.h>
61
62 #include <CoreFoundation/CoreFoundation.h>
63 #include <IOKit/usb/IOUSBLib.h>
64 #include <IOKit/IOCFPlugIn.h>
65
66 #include <pthread.h>
67
68 /*
69 * WAITEOF_DELAY is number of seconds we'll wait for responses from
70 * the printer after we've finished sending all the data
71 */
72 #define WAITEOF_DELAY 7
73 #define DEFAULT_TIMEOUT 60L
74
75 #define USB_INTERFACE_KIND CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID190)
76 #define kUSBLanguageEnglish 0x409
77
78 #define PRINTER_POLLING_INTERVAL 5 /* seconds */
79 #define INITIAL_LOG_INTERVAL (PRINTER_POLLING_INTERVAL)
80 #define SUBSEQUENT_LOG_INTERVAL (3*INITIAL_LOG_INTERVAL)
81
82 #define kUSBPrinterClassTypeID (CFUUIDGetConstantUUIDWithBytes(NULL, 0x06, 0x04, 0x7D, 0x16, 0x53, 0xA2, 0x11, 0xD6, 0x92, 0x06, 0x00, 0x30, 0x65, 0x52, 0x45, 0x92))
83 #define kUSBPrinterClassInterfaceID (CFUUIDGetConstantUUIDWithBytes(NULL, 0x03, 0x34, 0x6D, 0x74, 0x53, 0xA3, 0x11, 0xD6, 0x9E, 0xA1, 0x76, 0x30, 0x65, 0x52, 0x45, 0x92))
84
85 #define kUSBClassDriverProperty CFSTR("USB Printing Class")
86
87 #define kUSBGenericTOPrinterClassDriver CFSTR("/System/Library/Printers/Libraries/USBGenericTOPrintingClass.plugin")
88 #define kUSBPrinterClassDeviceNotOpen -9664 /*kPMInvalidIOMContext*/
89
90
91 #pragma mark -
92 /*
93 * Section 5.3 USB Printing Class spec
94 */
95 #define kUSBPrintingSubclass 1
96 #define kUSBPrintingProtocolNoOpen 0
97 #define kUSBPrintingProtocolUnidirectional 1
98 #define kUSBPrintingProtocolBidirectional 2
99
100 typedef IOUSBInterfaceInterface190 **printer_interface_t;
101
102 typedef struct iodevice_request_s /**** Device request ****/
103 {
104 UInt8 requestType;
105 UInt8 request;
106 UInt16 value;
107 UInt16 index;
108 UInt16 length;
109 void *buffer;
110 } iodevice_request_t;
111
112 typedef union { /**** Centronics status byte ****/
113 char b;
114 struct {
115 unsigned reserved0:2;
116 unsigned paperError:1;
117 unsigned select:1;
118 unsigned notError:1;
119 unsigned reserved1:3;
120 } status;
121 } centronics_status_t;
122
123 typedef struct classdriver_context_s /**** Classdriver context ****/
124 {
125 IUNKNOWN_C_GUTS;
126 CFPlugInRef plugin; /* release plugin */
127 IUnknownVTbl **factory; /* Factory */
128 void *vendorReference; /* vendor class specific usage */
129 UInt32 location; /* unique location in bus topology */
130 UInt8 interfaceNumber; /* Interface number */
131 UInt16 vendorID; /* Vendor id */
132 UInt16 productID; /* Product id */
133 printer_interface_t interface; /* identify the device to IOKit */
134 UInt8 outpipe; /* mandatory bulkOut pipe */
135 UInt8 inpipe; /* optional bulkIn pipe */
136
137 /* general class requests */
138 kern_return_t (*DeviceRequest)( struct classdriver_context_s **printer, iodevice_request_t *iorequest, UInt16 timeout );
139 kern_return_t (*GetString)( struct classdriver_context_s **printer, UInt8 whichString, UInt16 language, UInt16 timeout, CFStringRef *result );
140
141 /* standard printer class requests */
142 kern_return_t (*SoftReset)( struct classdriver_context_s **printer, UInt16 timeout );
143 kern_return_t (*GetCentronicsStatus)( struct classdriver_context_s **printer, centronics_status_t *result, UInt16 timeout );
144 kern_return_t (*GetDeviceID)( struct classdriver_context_s **printer, CFStringRef *devid, UInt16 timeout );
145
146 /* standard bulk device requests */
147 kern_return_t (*ReadPipe)( struct classdriver_context_s **printer, UInt8 *buffer, UInt32 *count );
148 kern_return_t (*WritePipe)( struct classdriver_context_s **printer, UInt8 *buffer, UInt32 *count, Boolean eoj );
149
150 /* interface requests */
151 kern_return_t (*Open)( struct classdriver_context_s **printer, UInt32 location, UInt8 protocol );
152 kern_return_t (*Abort)( struct classdriver_context_s **printer );
153 kern_return_t (*Close)( struct classdriver_context_s **printer );
154
155 /* initialize and terminate */
156 kern_return_t (*Initialize)( struct classdriver_context_s **printer, struct classdriver_context_s **baseclass );
157 kern_return_t (*Terminate)( struct classdriver_context_s **printer );
158
159 } classdriver_context_t;
160
161
162 typedef Boolean (*iterator_callback_t)(void *refcon, io_service_t obj);
163
164 typedef struct iterator_reference_s { /**** Iterator reference data */
165 iterator_callback_t callback;
166 void *userdata;
167 Boolean keepRunning;
168 } iterator_reference_t;
169
170 typedef struct printer_data_s { /**** Printer context data ****/
171 io_service_t printerObj;
172 classdriver_context_t **printerDriver;
173
174 pthread_cond_t readCompleteCondition;
175 pthread_mutex_t readMutex;
176 int done;
177
178 const char *uri;
179 CFStringRef make;
180 CFStringRef model;
181 CFStringRef serial;
182
183 UInt32 location;
184 Boolean waitEOF;
185
186 } printer_data_t;
187
188
189 /*
190 * Local functions...
191 */
192
193 static Boolean list_device_callback(void *refcon, io_service_t obj);
194 static Boolean find_device_callback(void *refcon, io_service_t obj);
195 static void iterate_printers(iterator_callback_t callBack, void *userdata);
196 static void device_added(void *userdata, io_iterator_t iterator);
197 static void copy_deviceinfo(CFStringRef deviceIDString, CFStringRef *make, CFStringRef *model, CFStringRef *serial);
198 static void release_deviceinfo(CFStringRef *make, CFStringRef *model, CFStringRef *serial);
199 static kern_return_t load_classdriver(CFStringRef driverPath, printer_interface_t intf, classdriver_context_t ***driver);
200 static kern_return_t unload_classdriver(classdriver_context_t ***classDriver);
201 static kern_return_t load_printerdriver(printer_data_t *printer);
202 static kern_return_t registry_open(printer_data_t *printer);
203 static kern_return_t registry_close(printer_data_t *printer);
204 static OSStatus copy_deviceid(classdriver_context_t **printer, CFStringRef *deviceID);
205 static void copy_devicestring(io_service_t usbInterface, CFStringRef *deviceID, UInt32 *deviceLocation);
206 static CFStringRef copy_value_for_key(CFStringRef deviceID, CFStringRef *keys);
207 static void parse_options(const char *options, char *serial, UInt32 *location, Boolean *waitEOF);
208 static void setup_cfLanguage(void);
209 static void *read_thread(void *reference);
210
211
212 #if defined(__i386__)
213 static pid_t child_pid; /* Child PID */
214 static void run_ppc_backend(int argc, char *argv[], int fd); /* Starts child backend process running as a ppc executable */
215 static void sigterm_handler(int sig); /* SIGTERM handler */
216 #endif /* __i386__ */
217
218 #ifdef PARSE_PS_ERRORS
219 static const char *next_line (const char *buffer);
220 static void parse_pserror (char *sockBuffer, int len);
221 #endif /* PARSE_PS_ERRORS */
222
223 #pragma mark -
224
225 /*
226 * 'list_devices()' - List all USB devices.
227 */
228
229 void list_devices()
230 {
231 puts("direct usb \"Unknown\" \"USB Printer (usb)\"");
232 iterate_printers(list_device_callback, NULL);
233 }
234
235
236 /*
237 * 'print_device()' - Print a file to a USB device.
238 */
239
240 int /* O - Exit status */
241 print_device(const char *uri, /* I - Device URI */
242 const char *hostname, /* I - Hostname/manufacturer */
243 const char *resource, /* I - Resource/modelname */
244 const char *options, /* I - Device options/serial number */
245 int fd, /* I - File descriptor to print */
246 int copies, /* I - Copies to print */
247 int argc, /* I - Number of command-line arguments (6 or 7) */
248 char *argv[]) /* I - Command-line arguments */
249 {
250 printer_data_t printer_data = { 0x0 }; /* Printer context */
251 char serial[1024]; /* Serial number buffer */
252 OSStatus status = noErr; /* Function results */
253 pthread_t thr; /* Read thread */
254 char buffer[2048]; /* Write buffer */
255 int thread_created = 0; /* Thread created? */
256 int countdown = INITIAL_LOG_INTERVAL; /* Logging interval */
257 pthread_cond_t *readCompleteConditionPtr = NULL; /* Read complete condition */
258 pthread_mutex_t *readMutexPtr = NULL; /* Read mutex */
259
260 setup_cfLanguage();
261 parse_options(options, serial, &printer_data.location, &printer_data.waitEOF);
262
263 if (resource[0] == '/')
264 resource++;
265
266 printer_data.uri = uri;
267 printer_data.make = CFStringCreateWithCString(NULL, hostname, kCFStringEncodingUTF8);
268 printer_data.model = CFStringCreateWithCString(NULL, resource, kCFStringEncodingUTF8);
269 printer_data.serial = CFStringCreateWithCString(NULL, serial, kCFStringEncodingUTF8);
270
271 fputs("STATE: +connecting-to-device\n", stderr);
272
273 do {
274 if (printer_data.printerObj != 0x0) {
275 IOObjectRelease(printer_data.printerObj);
276 unload_classdriver(&printer_data.printerDriver);
277 printer_data.printerObj = 0x0;
278 printer_data.printerDriver = 0x0;
279 }
280
281 fprintf(stderr, "INFO: Looking for '%s %s'\n", hostname, resource);
282 iterate_printers(find_device_callback, &printer_data);
283
284 fprintf(stderr, "INFO: Opening Connection\n");
285 status = registry_open(&printer_data);
286 #if defined(__i386__)
287 /*
288 * If we were unable to load the class drivers for this printer it's probably because they're ppc-only.
289 * In this case try to fork & exec this backend as a ppc executable so we can use them...
290 */
291 if (status == -2 /* kPMInvalidIOMContext */) {
292 run_ppc_backend(argc, argv, fd);
293 /* Never returns here */
294 }
295 #endif /* __i386__ */
296
297 if (status != noErr) {
298 sleep( PRINTER_POLLING_INTERVAL );
299 countdown -= PRINTER_POLLING_INTERVAL;
300 if ( countdown <= 0 ) {
301 fprintf(stderr, "INFO: Printer busy (status:0x%08x)\n", (int)status);
302 countdown = SUBSEQUENT_LOG_INTERVAL; /* subsequent log entries, every 15 seconds */
303 }
304 }
305 } while (status != noErr);
306
307 fputs("STATE: -connecting-to-device\n", stderr);
308
309 /*
310 * Now that we are "connected" to the port, ignore SIGTERM so that we
311 * can finish out any page data the driver sends (e.g. to eject the
312 * current page... Only ignore SIGTERM if we are printing data from
313 * stdin (otherwise you can't cancel raw jobs...)
314 */
315
316 if (!fd) {
317 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
318 sigset(SIGTERM, SIG_IGN);
319 #elif defined(HAVE_SIGACTION)
320 memset(&action, 0, sizeof(action));
321
322 sigemptyset(&action.sa_mask);
323 action.sa_handler = SIG_IGN;
324 sigaction(SIGTERM, &action, NULL);
325 #else
326 signal(SIGTERM, SIG_IGN);
327 #endif /* HAVE_SIGSET */
328 }
329
330 if (status == noErr) {
331 if (pthread_cond_init(&printer_data.readCompleteCondition, NULL) == 0)
332 readCompleteConditionPtr = &printer_data.readCompleteCondition;
333
334 if (pthread_mutex_init(&printer_data.readMutex, NULL) == 0)
335 readMutexPtr = &printer_data.readMutex;
336
337 if (pthread_create(&thr, NULL, read_thread, &printer_data) == 0)
338 thread_created = 1;
339
340 if (thread_created == 0)
341 fprintf(stderr, "WARNING: Couldn't create read channel\n");
342 }
343
344 /*
345 * The main thread sends the print file...
346 */
347
348 while (status == noErr && copies-- > 0) {
349 UInt32 wbytes; /* Number of bytes written */
350 ssize_t nbytes; /* Number of bytes read */
351 off_t tbytes = 0; /* Total number of bytes written */
352
353 fprintf(stderr, "INFO: Sending data\n");
354
355 if (STDIN_FILENO != fd) {
356 fputs("PAGE: 1 1", stderr);
357 lseek( fd, 0, SEEK_SET );
358 }
359
360 while (status == noErr && (nbytes = read(fd, buffer, sizeof(buffer))) > 0) {
361 char *bufptr = buffer;
362 tbytes += nbytes;
363
364 while (nbytes > 0 && status == noErr) {
365 wbytes = nbytes;
366 status = (*(printer_data.printerDriver))->WritePipe( printer_data.printerDriver, (UInt8*)bufptr, &wbytes, 0 /* nbytes > wbytes? 0: feof(fp) */ );
367 if (wbytes < 0 || noErr != status) {
368 OSStatus err = (*(printer_data.printerDriver))->Abort(printer_data.printerDriver);
369 fprintf(stderr, "ERROR: %ld: Unable to send print file to printer (canceled:%ld)\n", status, err);
370 break;
371 }
372
373 nbytes -= wbytes;
374 bufptr += wbytes;
375 }
376
377 if (fd != 0 && status == noErr)
378 fprintf(stderr, "DEBUG: Sending print file, %qd bytes...\n", (off_t)tbytes);
379 }
380 }
381
382 if (thread_created) {
383 /* Signal the read thread that we are done... */
384 printer_data.done = 1;
385
386 /* Give the read thread WAITEOF_DELAY seconds to complete all the data. If
387 * we are not signaled in that time then force the thread to exit by setting
388 * the waiteof to be false. Plese note that this relies on us using the timeout
389 * class driver.
390 */
391 struct timespec sleepUntil = { time(NULL) + WAITEOF_DELAY, 0 };
392 pthread_mutex_lock(&printer_data.readMutex);
393 if (pthread_cond_timedwait(&printer_data.readCompleteCondition, &printer_data.readMutex, (const struct timespec *)&sleepUntil) != 0)
394 printer_data.waitEOF = false;
395 pthread_mutex_unlock(&printer_data.readMutex);
396 pthread_join( thr,NULL); /* wait for the child thread to return */
397 }
398
399 /*
400 * Close the connection and input file and general clean up...
401 */
402 registry_close(&printer_data);
403
404 if (STDIN_FILENO != fd)
405 close(fd);
406
407 if (readCompleteConditionPtr != NULL)
408 pthread_cond_destroy(&printer_data.readCompleteCondition);
409
410 if (readMutexPtr != NULL)
411 pthread_mutex_destroy(&printer_data.readMutex);
412
413 if (printer_data.make != NULL)
414 CFRelease(printer_data.make);
415
416 if (printer_data.model != NULL)
417 CFRelease(printer_data.model);
418
419 if (printer_data.serial != NULL)
420 CFRelease(printer_data.serial);
421
422 if (printer_data.printerObj != 0x0)
423 IOObjectRelease(printer_data.printerObj);
424
425 return status;
426 }
427
428 #pragma mark -
429 /*
430 * 'list_device_callback()' - list_device iterator callback.
431 */
432
433 static Boolean list_device_callback(void *refcon, io_service_t obj)
434 {
435 Boolean keepRunning = (obj != 0x0);
436
437 if (keepRunning) {
438 CFStringRef deviceIDString = NULL;
439 UInt32 deviceLocation = 0;
440
441 copy_devicestring(obj, &deviceIDString, &deviceLocation);
442 if (deviceIDString != NULL) {
443 CFStringRef make = NULL, model = NULL, serial = NULL;
444 char uristr[1024], makestr[1024], modelstr[1024], serialstr[1024], optionsstr[1024];
445
446 copy_deviceinfo(deviceIDString, &make, &model, &serial);
447
448 modelstr[0] = '/';
449
450 CFStringGetCString(make, makestr, sizeof(makestr), kCFStringEncodingUTF8);
451 CFStringGetCString(model, &modelstr[1], sizeof(modelstr)-1, kCFStringEncodingUTF8);
452
453 optionsstr[0] = '\0';
454 if (serial != NULL)
455 {
456 CFStringGetCString(serial, serialstr, sizeof(serialstr), kCFStringEncodingUTF8);
457 snprintf(optionsstr, sizeof(optionsstr), "?serial=%s", serialstr);
458 }
459 else if (deviceLocation != 0)
460 {
461 snprintf(optionsstr, sizeof(optionsstr), "?location=%lx", deviceLocation);
462 }
463
464 httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
465 strncat(uristr, optionsstr, sizeof(uristr));
466
467 printf("direct %s \"%s %s\" \"%s\"\n", uristr, makestr, &modelstr[1], &modelstr[1]);
468
469 release_deviceinfo(&make, &model, &serial);
470 CFRelease(deviceIDString);
471 }
472 }
473
474 return keepRunning;
475 }
476
477
478 /*
479 * 'find_device_callback()' - print_device iterator callback.
480 */
481
482 static Boolean find_device_callback(void *refcon, io_service_t obj)
483 {
484 Boolean keepLooking = true;
485
486 if (obj != 0x0 && refcon != NULL) {
487 CFStringRef idString = NULL;
488 UInt32 location = -1;
489 printer_data_t *userData = (printer_data_t *)refcon;
490
491 copy_devicestring(obj, &idString, &location);
492 if (idString != NULL) {
493 CFStringRef make = NULL, model = NULL, serial = NULL;
494
495 copy_deviceinfo(idString, &make, &model, &serial);
496 if (CFStringCompare(make, userData->make, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
497 if (CFStringCompare(model, userData->model, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
498 if (userData->serial != NULL) {
499 if (serial != NULL && CFStringCompare(model, userData->model, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
500 IOObjectRetain(obj);
501 userData->printerObj = obj;
502 keepLooking = false;
503 }
504 }
505 else {
506 if (userData->printerObj != 0) {
507 IOObjectRetain(userData->printerObj);
508 }
509 userData->printerObj = obj;
510 IOObjectRetain(obj);
511
512 if (userData->location == 0 || userData->location == location) {
513 keepLooking = false;
514 }
515 }
516 }
517 }
518
519 release_deviceinfo(&make, &model, &serial);
520 CFRelease(idString);
521 }
522 }
523 else {
524 keepLooking = (refcon != NULL && ((printer_data_t *)refcon)->printerObj == 0);
525 }
526
527 return keepLooking;
528 }
529
530
531 #pragma mark -
532 /*
533 * 'iterate_printers()' - iterate over all the printers.
534 */
535
536 static void iterate_printers(iterator_callback_t callBack, void *userdata)
537 {
538 mach_port_t masterPort = 0x0;
539 kern_return_t kr = IOMasterPort (bootstrap_port, &masterPort);
540
541 if (kr == kIOReturnSuccess && masterPort != 0x0) {
542 io_iterator_t addIterator = 0x0;
543
544 iterator_reference_t reference = { callBack, userdata, true };
545 IONotificationPortRef addNotification = IONotificationPortCreate(masterPort);
546
547 int klass = kUSBPrintingClass;
548 int subklass = kUSBPrintingSubclass;
549
550 CFNumberRef usb_klass = CFNumberCreate(NULL, kCFNumberIntType, &klass);
551 CFNumberRef usb_subklass = CFNumberCreate(NULL, kCFNumberIntType, &subklass);
552 CFMutableDictionaryRef usbPrinterMatchDictionary = IOServiceMatching(kIOUSBInterfaceClassName);
553
554 CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceClass"), usb_klass);
555 CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceSubClass"), usb_subklass);
556
557 CFRelease(usb_klass);
558 CFRelease(usb_subklass);
559
560 kr = IOServiceAddMatchingNotification(addNotification, kIOMatchedNotification, usbPrinterMatchDictionary, &device_added, &reference, &addIterator);
561 if (addIterator != 0x0) {
562 device_added (&reference, addIterator);
563
564 if (reference.keepRunning) {
565 CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(addNotification), kCFRunLoopDefaultMode);
566 CFRunLoopRun();
567 }
568 IOObjectRelease(addIterator);
569 }
570 mach_port_deallocate(mach_task_self(), masterPort);
571 }
572 }
573
574
575 /*
576 * 'device_added()' - device added notifier.
577 */
578
579 static void device_added(void *userdata, io_iterator_t iterator)
580 {
581 iterator_reference_t *reference = userdata;
582
583 io_service_t obj;
584 while (reference->keepRunning && (obj = IOIteratorNext(iterator)) != 0x0) {
585 if (reference->callback != NULL) {
586 reference->keepRunning = reference->callback(reference->userdata, obj);
587 }
588 IOObjectRelease(obj);
589 }
590
591 /* One last call to the call back now that we are not longer have printers left to iterate...
592 */
593 if (reference->keepRunning)
594 reference->keepRunning = reference->callback(reference->userdata, 0x0);
595
596 if (!reference->keepRunning) {
597 CFRunLoopStop(CFRunLoopGetCurrent());
598 }
599 }
600
601
602 #pragma mark -
603 /*
604 * 'copy_deviceinfo()' - Copy strings from the 1284 device ID.
605 */
606
607 static void copy_deviceinfo(CFStringRef deviceIDString, CFStringRef *make, CFStringRef *model, CFStringRef *serial)
608 {
609 CFStringRef modelKeys[] = { CFSTR("MDL:"), CFSTR("MODEL:"), NULL };
610 CFStringRef makeKeys[] = { CFSTR("MFG:"), CFSTR("MANUFACTURER:"), NULL };
611 CFStringRef serialKeys[] = { CFSTR("SN:"), CFSTR("SERN:"), NULL };
612
613 if (make != NULL)
614 *make = copy_value_for_key(deviceIDString, makeKeys);
615 if (model != NULL)
616 *model = copy_value_for_key(deviceIDString, modelKeys);
617 if (serial != NULL)
618 *serial = copy_value_for_key(deviceIDString, serialKeys);
619 }
620
621
622 /*
623 * 'release_deviceinfo()' - Release deviceinfo strings.
624 */
625
626 static void release_deviceinfo(CFStringRef *make, CFStringRef *model, CFStringRef *serial)
627 {
628 if (make != NULL && *make != NULL) {
629 CFRelease(*make);
630 *make = NULL;
631 }
632
633 if (model != NULL && *model != NULL) {
634 CFRelease(*model);
635 *model = NULL;
636 }
637
638 if (serial != NULL && *serial != NULL) {
639 CFRelease(*serial);
640 *serial = NULL;
641 }
642 }
643
644
645 #pragma mark -
646 /*
647 * 'load_classdriver()' - Load a classdriver.
648 */
649
650 static kern_return_t load_classdriver(CFStringRef driverPath, printer_interface_t intf, classdriver_context_t ***printerDriver)
651 {
652 kern_return_t kr = kUSBPrinterClassDeviceNotOpen;
653 classdriver_context_t **driver = NULL;
654 CFStringRef bundle = (driverPath == NULL ? kUSBGenericTOPrinterClassDriver : driverPath);
655
656 if ( NULL != bundle ) {
657 CFURLRef url = CFURLCreateWithFileSystemPath(NULL, bundle, kCFURLPOSIXPathStyle, true);
658 CFPlugInRef plugin = (url != NULL ? CFPlugInCreate(NULL, url) : NULL);
659
660 if (url != NULL)
661 CFRelease(url);
662
663 if (plugin != NULL) {
664 CFArrayRef factories = CFPlugInFindFactoriesForPlugInTypeInPlugIn(kUSBPrinterClassTypeID, plugin);
665 if (factories != NULL && CFArrayGetCount(factories) > 0) {
666 CFUUIDRef factoryID = CFArrayGetValueAtIndex(factories, 0);
667 IUnknownVTbl **iunknown = CFPlugInInstanceCreate(NULL, factoryID, kUSBPrinterClassTypeID);
668 if (NULL != iunknown) {
669 kr = (*iunknown)->QueryInterface(iunknown, CFUUIDGetUUIDBytes(kUSBPrinterClassInterfaceID), (LPVOID *)&driver);
670 if (kr == kIOReturnSuccess && driver != NULL) {
671 classdriver_context_t **genericDriver = NULL;
672 if (driverPath != NULL && CFStringCompare(driverPath, kUSBGenericTOPrinterClassDriver, 0) != kCFCompareEqualTo) {
673 kr = load_classdriver(NULL, intf, &genericDriver);
674 }
675
676 if (kr == kIOReturnSuccess) {
677 (*driver)->interface = intf;
678 (*driver)->Initialize(driver, genericDriver);
679
680 (*driver)->plugin = plugin;
681 (*driver)->interface = intf;
682 *printerDriver = driver;
683 }
684 }
685 (*iunknown)->Release(iunknown);
686 }
687 CFRelease(factories);
688 }
689 }
690 }
691
692 #ifdef DEBUG
693 char bundlestr[1024];
694 CFStringGetCString(bundle, bundlestr, sizeof(bundlestr), kCFStringEncodingUTF8);
695 fprintf(stderr, "DEBUG:load_classdriver(%s) (kr:0x%08x)\n", bundlestr, (int)kr);
696 #endif /* DEBUG */
697
698 return kr;
699 }
700
701
702 /*
703 * 'unload_classdriver()' - Unload a classdriver.
704 */
705
706 static kern_return_t unload_classdriver(classdriver_context_t ***classDriver)
707 {
708 if (*classDriver != NULL) {
709 (**classDriver)->Release(*classDriver);
710 *classDriver = NULL;
711 }
712
713 return kIOReturnSuccess;
714 }
715
716
717 /*
718 * 'load_printerdriver()' - Load a vendor's (or generic) classdriver.
719 */
720
721 static kern_return_t load_printerdriver(printer_data_t *printer)
722 {
723 IOCFPlugInInterface **iodev = NULL;
724 SInt32 score;
725
726 kern_return_t kr = IOCreatePlugInInterfaceForService(printer->printerObj, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
727 if (kr == kIOReturnSuccess) {
728 printer_interface_t intf;
729 HRESULT res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &intf);
730 if (res == noErr) {
731 CFMutableDictionaryRef properties = NULL;
732
733 kr = IORegistryEntryCreateCFProperties(printer->printerObj, &properties, NULL, kNilOptions);
734 if (kr == kIOReturnSuccess) {
735 CFStringRef driverBundlePath = NULL;
736 if (properties != NULL) {
737 driverBundlePath = (CFStringRef) CFDictionaryGetValue(properties, kUSBClassDriverProperty);
738 }
739 kr = load_classdriver(driverBundlePath, intf, &printer->printerDriver);
740 }
741
742 if (kr != kIOReturnSuccess)
743 (*intf)->Release(intf);
744 }
745 IODestroyPlugInInterface(iodev);
746 }
747 return kr;
748 }
749
750
751 /*
752 * 'registry_open()' - Open a connection to the printer.
753 */
754
755 static kern_return_t registry_open(printer_data_t *printer)
756 {
757 kern_return_t kr = load_printerdriver(printer);
758 if (kr != kIOReturnSuccess) {
759 kr = -2;
760 }
761
762 if (printer->printerDriver != NULL) {
763 kr = (*(printer->printerDriver))->Open(printer->printerDriver, printer->location, kUSBPrintingProtocolBidirectional);
764 if (kr != kIOReturnSuccess || (*(printer->printerDriver))->interface == NULL) {
765 kr = (*(printer->printerDriver))->Open(printer->printerDriver, printer->location, kUSBPrintingProtocolUnidirectional);
766 if (kr == kIOReturnSuccess) {
767 if ((*(printer->printerDriver))->interface == NULL) {
768 (*(printer->printerDriver))->Close(printer->printerDriver);
769 kr = -1;
770 }
771 }
772 }
773 }
774
775 if (kr != kIOReturnSuccess) {
776 unload_classdriver(&printer->printerDriver);
777 }
778
779 return kr;
780 }
781
782
783 /*
784 * 'registry_close()' - Close the connection to the printer.
785 */
786
787 static kern_return_t registry_close(printer_data_t *printer)
788 {
789 if (printer->printerDriver != NULL) {
790 (*(printer->printerDriver))->Close(printer->printerDriver);
791 }
792 unload_classdriver(&printer->printerDriver);
793 return kIOReturnSuccess;
794 }
795
796
797 /*
798 * 'copy_deviceid()' - Copy the 1284 device id string.
799 */
800
801 static OSStatus copy_deviceid(classdriver_context_t **printer, CFStringRef *deviceID)
802 {
803 CFStringRef devID = NULL,
804
805 deviceMake = NULL,
806 deviceModel = NULL,
807 deviceSerial = NULL;
808
809 OSStatus err = (*printer)->GetDeviceID(printer, &devID, DEFAULT_TIMEOUT);
810
811 copy_deviceinfo(devID, &deviceMake, &deviceModel, &deviceSerial);
812
813 if (deviceMake == NULL || deviceModel == NULL || deviceSerial == NULL) {
814 IOUSBDeviceDescriptor desc;
815 iodevice_request_t request;
816
817 request.requestType = USBmakebmRequestType( kUSBIn, kUSBStandard, kUSBDevice );
818 request.request = kUSBRqGetDescriptor;
819 request.value = (kUSBDeviceDesc << 8) | 0;
820 request.index = 0;
821 request.length = sizeof(desc);
822 request.buffer = &desc;
823 err = (*printer)->DeviceRequest(printer, &request, DEFAULT_TIMEOUT);
824 if (err == kIOReturnSuccess) {
825 CFMutableStringRef newDevID = CFStringCreateMutable(NULL, 0);
826
827 if (deviceMake == NULL) {
828 CFStringRef data = NULL;
829 err = (*printer)->GetString(printer, desc.iManufacturer, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &data);
830 if (data != NULL) {
831 CFStringAppendFormat(newDevID, NULL, CFSTR("MFG:%@;"), data);
832 CFRelease(data);
833 }
834 }
835
836 if (deviceModel == NULL) {
837 CFStringRef data = NULL;
838 err = (*printer)->GetString(printer, desc.iProduct, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &data);
839 if (data != NULL) {
840 CFStringAppendFormat(newDevID, NULL, CFSTR("MDL:%@;"), data);
841 CFRelease(data);
842 }
843 }
844
845 if (deviceSerial == NULL && desc.iSerialNumber != 0) {
846 CFStringRef data = NULL;
847 err = (*printer)->GetString(printer, desc.iSerialNumber, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &data);
848 if (data != NULL) {
849 CFStringAppendFormat(newDevID, NULL, CFSTR("SERN:%@;"), data);
850 CFRelease(data);
851 }
852 }
853
854 if (devID != NULL) {
855 CFStringAppend(newDevID, devID);
856 CFRelease(devID);
857 }
858
859 *deviceID = newDevID;
860 }
861 }
862 else {
863 *deviceID = devID;
864 }
865 release_deviceinfo(&deviceMake, &deviceModel, &deviceSerial);
866
867 return err;
868 }
869
870
871 /*
872 * 'copy_devicestring()' - Copy the 1284 device id string.
873 */
874
875 static void copy_devicestring(io_service_t usbInterface, CFStringRef *deviceID, UInt32 *deviceLocation)
876 {
877 IOCFPlugInInterface **iodev = NULL;
878 SInt32 score;
879
880 kern_return_t kr = IOCreatePlugInInterfaceForService(usbInterface, kIOUSBInterfaceUserClientTypeID,
881 kIOCFPlugInInterfaceID, &iodev, &score);
882 if (kr == kIOReturnSuccess) {
883 printer_interface_t intf;
884
885 HRESULT res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &intf);
886 if (res == noErr) {
887 /* ignore the result for location id... */
888 (void)(*intf)->GetLocationID(intf, deviceLocation);
889
890 CFMutableDictionaryRef properties = NULL;
891 kr = IORegistryEntryCreateCFProperties(usbInterface, &properties, NULL, kNilOptions);
892 if (kIOReturnSuccess == kr) {
893 classdriver_context_t **klassDriver = NULL;
894 CFStringRef driverBundlePath = NULL;
895
896 if (properties != NULL) {
897 driverBundlePath = (CFStringRef) CFDictionaryGetValue(properties, kUSBClassDriverProperty);
898 }
899
900 kr = load_classdriver(driverBundlePath, intf, &klassDriver);
901 if (kr != kIOReturnSuccess && driverBundlePath != NULL)
902 kr = load_classdriver(NULL, intf, &klassDriver);
903 if (kr == kIOReturnSuccess && klassDriver != NULL) {
904 kr = copy_deviceid(klassDriver, deviceID);
905 }
906 unload_classdriver(&klassDriver);
907
908 if (properties != NULL)
909 CFRelease(properties);
910 }
911
912 /* (*intf)->Release(intf); */
913 }
914 IODestroyPlugInInterface(iodev);
915 }
916 }
917
918
919 #pragma mark -
920 /*
921 * 'copy_value_for_key()' - Copy value string associated with a key.
922 */
923
924 static CFStringRef copy_value_for_key(CFStringRef deviceID, CFStringRef *keys)
925 {
926 CFStringRef value = NULL;
927 CFArrayRef kvPairs = deviceID != NULL ? CFStringCreateArrayBySeparatingStrings(NULL, deviceID, CFSTR(";")) : NULL;
928 CFIndex max = kvPairs != NULL ? CFArrayGetCount(kvPairs) : 0;
929 CFIndex idx = 0;
930
931 while (idx < max && value == NULL) {
932 CFStringRef kvpair = CFArrayGetValueAtIndex(kvPairs, idx);
933 CFIndex idxx = 0;
934 while (keys[idxx] != NULL && value == NULL) {
935 CFRange range = CFStringFind(kvpair, keys[idxx], kCFCompareCaseInsensitive);
936 if (range.length != -1) {
937 if (range.location != 0) {
938 CFMutableStringRef theString = CFStringCreateMutableCopy(NULL, 0, kvpair);
939 CFStringTrimWhitespace(theString);
940 range = CFStringFind(theString, keys[idxx], kCFCompareCaseInsensitive);
941 if (range.location == 0) {
942 value = CFStringCreateWithSubstring(NULL, theString, CFRangeMake(range.length, CFStringGetLength(theString) - range.length));
943 }
944 CFRelease(theString);
945 }
946 else {
947 CFStringRef theString = CFStringCreateWithSubstring(NULL, kvpair, CFRangeMake(range.length, CFStringGetLength(kvpair) - range.length));
948 CFMutableStringRef theString2 = CFStringCreateMutableCopy(NULL, 0, theString);
949 CFRelease(theString);
950
951 CFStringTrimWhitespace(theString2);
952 value = theString2;
953 }
954 }
955 idxx++;
956 }
957 idx++;
958 }
959
960 if (kvPairs != NULL)
961 CFRelease(kvPairs);
962 return value;
963 }
964
965
966 #pragma mark -
967 /*
968 * 'parse_options()' - Parse uri options.
969 */
970
971 static void parse_options(const char *options, char *serial, UInt32 *location, Boolean *waitEOF)
972 {
973 char *serialnumber; /* ?serial=<serial> or ?location=<location> */
974 char optionName[255], /* Name of option */
975 value[255], /* Value of option */
976 *ptr; /* Pointer into name or value */
977
978 if (serial)
979 *serial = '\0';
980 if (location)
981 *location = 0;
982
983 if (!options)
984 return;
985
986 serialnumber = NULL;
987
988 while (*options != '\0') {
989 /* Get the name... */
990 for (ptr = optionName; *options && *options != '=' && *options != '+'; )
991 *ptr++ = *options++;
992
993 *ptr = '\0';
994 value[0] = '\0';
995
996 if (*options == '=') {
997 /* Get the value... */
998 options ++;
999
1000 for (ptr = value; *options && *options != '+';)
1001 *ptr++ = *options++;
1002
1003 *ptr = '\0';
1004
1005 if (*options == '+')
1006 options ++;
1007 }
1008 else if (*options == '+') {
1009 options ++;
1010 }
1011
1012 /*
1013 * Process the option...
1014 */
1015 if (strcasecmp(optionName, "waiteof") == 0) {
1016 if (strcasecmp(value, "on") == 0 ||
1017 strcasecmp(value, "yes") == 0 ||
1018 strcasecmp(value, "true") == 0) {
1019 *waitEOF = true;
1020 }
1021 else if (strcasecmp(value, "off") == 0 ||
1022 strcasecmp(value, "no") == 0 ||
1023 strcasecmp(value, "false") == 0) {
1024 *waitEOF = false;
1025 }
1026 else {
1027 fprintf(stderr, "WARNING: Boolean expected for waiteof option \"%s\"\n", value);
1028 }
1029 }
1030 else if (strcasecmp(optionName, "serial") == 0) {
1031 strcpy(serial, value);
1032 serialnumber = serial;
1033 }
1034 else if (strcasecmp(optionName, "location") == 0 && location) {
1035 *location = strtol(value, NULL, 16);
1036 }
1037 }
1038
1039 return;
1040 }
1041
1042
1043 /*!
1044 * @function setup_cfLanguage
1045 * @abstract Convert the contents of the CUPS 'LANG' environment
1046 * variable into a one element CF array of languages.
1047 *
1048 * @discussion Each submitted job comes with a natural language. CUPS passes
1049 * that language in an environment variable. We take that language
1050 * and jam it into the AppleLanguages array so that CF will use
1051 * it when reading localized resources. We need to do this before
1052 * any CF code reads and caches the languages array, so this function
1053 * should be called early in main()
1054 */
1055 static void setup_cfLanguage(void)
1056 {
1057 CFStringRef lang[1] = {NULL};
1058 CFArrayRef langArray = NULL;
1059 const char *requestedLang = NULL;
1060
1061 requestedLang = getenv("LANG");
1062 if (requestedLang != NULL) {
1063 lang[0] = CFStringCreateWithCString(kCFAllocatorDefault, requestedLang, kCFStringEncodingUTF8);
1064 langArray = CFArrayCreate(kCFAllocatorDefault, (const void **)lang, sizeof(lang) / sizeof(lang[0]), &kCFTypeArrayCallBacks);
1065
1066 CFPreferencesSetAppValue(CFSTR("AppleLanguages"), langArray, kCFPreferencesCurrentApplication);
1067 DEBUG_printf((stderr, "DEBUG: usb: AppleLanguages = \"%s\"\n", requestedLang));
1068
1069 CFRelease(lang[0]);
1070 CFRelease(langArray);
1071 } else {
1072 fprintf(stderr, "DEBUG: usb: LANG environment variable missing.\n");
1073 }
1074 }
1075
1076 #pragma mark -
1077 #if defined(__i386__)
1078 /*!
1079 * @function run_ppc_backend
1080 *
1081 * @abstract Starts child backend process running as a ppc executable.
1082 *
1083 * @result Never returns; always calls exit().
1084 *
1085 * @discussion
1086 */
1087 static void run_ppc_backend(int argc, char *argv[], int fd)
1088 {
1089 int i;
1090 int exitstatus = 0;
1091 int childstatus;
1092 pid_t waitpid_status;
1093 char *my_argv[32];
1094 char *usb_ppc_status;
1095
1096 /*
1097 * If we're running as i386 and couldn't load the class driver (because they'it's
1098 * ppc-only) then try to re-exec ourselves in ppc mode to try again. If we don't have
1099 * a ppc architecture we may be running i386 again so guard against this by setting
1100 * and testing an environment variable...
1101 */
1102 usb_ppc_status = getenv("USB_PPC_STATUS");
1103
1104 if (usb_ppc_status == NULL) {
1105 /* Catch SIGTERM if we are _not_ printing data from
1106 * stdin (otherwise you can't cancel raw jobs...)
1107 */
1108
1109 if (fd != 0) {
1110 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1111 sigset(SIGTERM, sigterm_handler);
1112 #elif defined(HAVE_SIGACTION)
1113 struct sigaction action; /* Actions for POSIX signals */
1114 memset(&action, 0, sizeof(action));
1115 sigaddset(&action.sa_mask, SIGTERM);
1116 action.sa_handler = sigterm_handler;
1117 sigaction(SIGTERM, &action, NULL);
1118 #else
1119 signal(SIGTERM, sigterm_handler);
1120 #endif /* HAVE_SIGSET */
1121 }
1122
1123 if ((child_pid = fork()) == 0) {
1124 /* Child comes here. */
1125 setenv("USB_PPC_STATUS", "1", false);
1126
1127 /* Tell the kernel we want the next exec call to favor the ppc architecture... */
1128 int mib[] = { CTL_KERN, KERN_AFFINITY, 1, 1 };
1129 int namelen = 4;
1130 sysctl(mib, namelen, NULL, NULL, NULL, 0);
1131
1132 /* Set up the arguments and call exec... */
1133 for (i = 0; i < argc && i < (sizeof(my_argv)/sizeof(my_argv[0])) - 1; i++)
1134 my_argv[i] = argv[i];
1135
1136 my_argv[i] = NULL;
1137
1138 execv("/usr/libexec/cups/backend/usb", my_argv);
1139
1140 fprintf(stderr, "DEBUG: execv: %s\n", strerror(errno));
1141 exitstatus = errno;
1142 }
1143 else if (child_pid > 0) {
1144 /* Parent comes here.
1145 *
1146 * Close the fds we won't be using then wait for the child backend to exit.
1147 */
1148 close(fd);
1149 close(1);
1150
1151 fprintf(stderr, "DEBUG: Started usb(ppc) backend (PID %d)\n", (int)child_pid);
1152
1153 while ((waitpid_status = waitpid(child_pid, &childstatus, 0)) == (pid_t)-1 && errno == EINTR)
1154 usleep(1000);
1155
1156 if (WIFSIGNALED(childstatus)) {
1157 exitstatus = WTERMSIG(childstatus);
1158 fprintf(stderr, "DEBUG: usb(ppc) backend %d crashed on signal %d!\n", child_pid, exitstatus);
1159 }
1160 else {
1161 if ((exitstatus = WEXITSTATUS(childstatus)) != 0)
1162 fprintf(stderr, "DEBUG: usb(ppc) backend %d stopped with status %d!\n", child_pid, exitstatus);
1163 else
1164 fprintf(stderr, "DEBUG: PID %d exited with no errors\n", child_pid);
1165 }
1166 }
1167 else {
1168 /* fork() error */
1169 fprintf(stderr, "DEBUG: fork: %s\n", strerror(errno));
1170 exitstatus = errno;
1171 }
1172 }
1173 else {
1174 fprintf(stderr, "DEBUG: usb child running i386 again\n");
1175 exitstatus = ENOENT;
1176 }
1177
1178 exit(exitstatus);
1179 }
1180
1181 /*
1182 * 'sigterm_handler()' - SIGTERM handler.
1183 */
1184
1185 static void sigterm_handler(int sig)
1186 {
1187 /* If we started a child process pass the signal on to it...
1188 */
1189 if (child_pid)
1190 kill(child_pid, sig);
1191
1192 exit(1);
1193 }
1194
1195 #endif /* __i386__ */
1196
1197
1198 #ifdef PARSE_PS_ERRORS
1199 /*
1200 * 'next_line()' - Find the next line in a buffer.
1201 */
1202
1203 static const char *next_line (const char *buffer)
1204 {
1205 const char *cptr, *lptr = NULL;
1206
1207 for (cptr = buffer; *cptr && lptr == NULL; cptr++)
1208 if (*cptr == '\n' || *cptr == '\r')
1209 lptr = cptr;
1210 return lptr;
1211 }
1212
1213
1214 /*
1215 * 'parse_pserror()' - Scan the backchannel data for postscript errors.
1216 */
1217
1218 static void parse_pserror (char *sockBuffer, int len)
1219 {
1220 static char gErrorBuffer[1024] = "";
1221 static char *gErrorBufferPtr = gErrorBuffer;
1222 static char *gErrorBufferEndPtr = gErrorBuffer + sizeof(gErrorBuffer);
1223
1224 char *pCommentBegin, *pCommentEnd, *pLineEnd;
1225 char *logLevel;
1226 char logstr[1024];
1227 int logstrlen;
1228
1229 if (gErrorBufferPtr + len > gErrorBufferEndPtr - 1)
1230 gErrorBufferPtr = gErrorBuffer;
1231 if (len > sizeof(gErrorBuffer) - 1)
1232 len = sizeof(gErrorBuffer) - 1;
1233
1234 memcpy(gErrorBufferPtr, (const void *)sockBuffer, len);
1235 gErrorBufferPtr += len;
1236 *(gErrorBufferPtr + 1) = '\0';
1237
1238
1239 pLineEnd = (char *)next_line((const char *)gErrorBuffer);
1240 while (pLineEnd != NULL) {
1241 *pLineEnd++ = '\0';
1242
1243 pCommentBegin = strstr(gErrorBuffer,"%%[");
1244 pCommentEnd = strstr(gErrorBuffer, "]%%");
1245 if (pCommentBegin != gErrorBuffer && pCommentEnd != NULL) {
1246 pCommentEnd += 3; /* Skip past "]%%" */
1247 *pCommentEnd = '\0'; /* There's always room for the nul */
1248
1249 if (strncasecmp(pCommentBegin, "%%[ Error:", 10) == 0)
1250 logLevel = "DEBUG";
1251 else if (strncasecmp(pCommentBegin, "%%[ Flushing", 12) == 0)
1252 logLevel = "DEBUG";
1253 else
1254 logLevel = "INFO";
1255
1256 if ((logstrlen = snprintf(logstr, sizeof(logstr), "%s: %s\n", logLevel, pCommentBegin)) >= sizeof(logstr)) {
1257 /* If the string was trucnated make sure it has a linefeed before the nul */
1258 logstrlen = sizeof(logstr) - 1;
1259 logstr[logstrlen - 1] = '\n';
1260 }
1261 write(STDERR_FILENO, logstr, logstrlen);
1262 }
1263
1264 /* move everything over... */
1265 strcpy(gErrorBuffer, pLineEnd);
1266 gErrorBufferPtr = gErrorBuffer;
1267 pLineEnd = (char *)next_line((const char *)gErrorBuffer);
1268 }
1269 }
1270 #endif /* PARSE_PS_ERRORS */
1271
1272
1273 /*
1274 * 'read_thread()' - A thread to read the backchannel data.
1275 */
1276
1277 static void *read_thread(void *reference)
1278 {
1279 /* post a read to the device and write results to stdout
1280 * the final pending read will be Aborted in the main thread
1281 */
1282 UInt8 readbuffer[512];
1283 UInt32 rbytes;
1284 kern_return_t readstatus;
1285 printer_data_t *userData = (printer_data_t *)reference;
1286 classdriver_context_t **classdriver = userData->printerDriver;
1287 struct mach_timebase_info timeBaseInfo;
1288 uint64_t start,
1289 delay;
1290
1291 /* Calculate what 250 milliSeconds are in mach absolute time...
1292 */
1293 mach_timebase_info(&timeBaseInfo);
1294 delay = ((uint64_t)250000000 * (uint64_t)timeBaseInfo.denom) / (uint64_t)timeBaseInfo.numer;
1295
1296 do {
1297 /* Remember when we started so we can throttle the loop after the read call...
1298 */
1299 start = mach_absolute_time();
1300
1301 rbytes = sizeof(readbuffer) - 1;
1302 readstatus = (*classdriver)->ReadPipe( classdriver, readbuffer, &rbytes );
1303 if ( kIOReturnSuccess == readstatus && rbytes > 0 ) {
1304
1305 cupsBackChannelWrite((char*)readbuffer, rbytes, 1.0);
1306
1307 /* cntrl-d is echoed by the printer.
1308 * NOTES:
1309 * Xerox Phaser 6250D doesn't echo the cntrl-d.
1310 * Xerox Phaser 6250D doesn't always send the product query.
1311 */
1312 if (userData->waitEOF && readbuffer[rbytes-1] == 0x4)
1313 break;
1314 #ifdef PARSE_PS_ERRORS
1315 parse_pserror(readbuffer, rbytes);
1316 #endif
1317 }
1318
1319 /* Make sure this loop executes no more than once every 250 miliseconds...
1320 */
1321 if ((readstatus != kIOReturnSuccess || rbytes == 0) && (userData->waitEOF || !userData->done))
1322 mach_wait_until(start + delay);
1323
1324 } while ( userData->waitEOF || !userData->done ); /* Abort from main thread tests error here */
1325
1326 /* Let the other thread (main thread) know that we have completed the read thread...
1327 */
1328 pthread_mutex_lock(&userData->readMutex);
1329 pthread_cond_signal(&userData->readCompleteCondition);
1330 pthread_mutex_unlock(&userData->readMutex);
1331
1332 return NULL;
1333 }
1334
1335
1336 /*
1337 * End of "$Id: usb-darwin.c 5373 2006-04-06 20:03:32Z mike $".
1338 */