]> 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 6591 2007-06-21 20:35:28Z mike $"
3 *
4 * Copyright © 2005-2007 Apple 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 * Contents:
45 *
46 * list_devices() - List all USB devices.
47 * print_device() - Print a file to a USB device.
48 * sidechannel_thread() - Thread to handle side-channel requests.
49 * read_thread() - Thread to read the backchannel data on.
50 * list_device_cb() - list_device iterator callback.
51 * find_device_cb() - print_device iterator callback.
52 * status_timer_cb() - Status timer callback.
53 * iterate_printers() - Iterate over all the printers.
54 * device_added() - Device added notifier.
55 * copy_deviceinfo() - Copy strings from the 1284 device ID.
56 * release_deviceinfo() - Release deviceinfo strings.
57 * load_classdriver() - Load a classdriver.
58 * unload_classdriver() - Unload a classdriver.
59 * load_printerdriver() - Load vendor's classdriver.
60 * registry_open() - Open a connection to the printer.
61 * registry_close() - Close the connection to the printer.
62 * copy_deviceid() - Copy the 1284 device id string.
63 * copy_devicestring() - Copy the 1284 device id string.
64 * copy_value_for_key() - Copy value string associated with a key.
65 * cfstr_create_trim() - Create CFString and trim whitespace characters.
66 * parse_options() - Parse uri options.
67 * setup_cfLanguage() - Create AppleLanguages array from LANG environment var.
68 * run_ppc_backend() - Re-exec i386 backend as ppc.
69 * sigterm_handler() - SIGTERM handler.
70 * next_line() - Find the next line in a buffer.
71 * parse_pserror() - Scan the backchannel data for postscript errors.
72 * get_device_id() - Return IEEE-1284 device ID.
73 */
74
75 /*
76 * Include necessary headers.
77 */
78
79 #include <stdio.h>
80 #include <stdlib.h>
81 #include <errno.h>
82 #include <signal.h>
83 #include <fcntl.h>
84 #include <termios.h>
85 #include <unistd.h>
86 #include <sys/sysctl.h>
87 #include <libgen.h>
88 #include <mach/mach.h>
89 #include <mach/mach_error.h>
90 #include <mach/mach_time.h>
91 #include <cups/debug.h>
92 #include <cups/sidechannel.h>
93 #include <cups/i18n.h>
94
95 #include <CoreFoundation/CoreFoundation.h>
96 #include <IOKit/usb/IOUSBLib.h>
97 #include <IOKit/IOCFPlugIn.h>
98
99 #include <pthread.h>
100
101
102 /*
103 * WAIT_EOF_DELAY is number of seconds we'll wait for responses from
104 * the printer after we've finished sending all the data
105 */
106 #define WAIT_EOF_DELAY 7
107 #define DEFAULT_TIMEOUT 60L
108
109 #define USB_INTERFACE_KIND CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID190)
110 #define kUSBLanguageEnglish 0x409
111
112 #define PRINTER_POLLING_INTERVAL 5 /* seconds */
113 #define INITIAL_LOG_INTERVAL PRINTER_POLLING_INTERVAL
114 #define SUBSEQUENT_LOG_INTERVAL 3 * INITIAL_LOG_INTERVAL
115
116 #define kUSBPrinterClassTypeID CFUUIDGetConstantUUIDWithBytes(NULL, 0x06, 0x04, 0x7D, 0x16, 0x53, 0xA2, 0x11, 0xD6, 0x92, 0x06, 0x00, 0x30, 0x65, 0x52, 0x45, 0x92)
117 #define kUSBPrinterClassInterfaceID CFUUIDGetConstantUUIDWithBytes(NULL, 0x03, 0x34, 0x6D, 0x74, 0x53, 0xA3, 0x11, 0xD6, 0x9E, 0xA1, 0x76, 0x30, 0x65, 0x52, 0x45, 0x92)
118
119 #define kUSBClassDriverProperty CFSTR("USB Printing Class")
120
121 #define kUSBGenericTOPrinterClassDriver CFSTR("/System/Library/Printers/Libraries/USBGenericTOPrintingClass.plugin")
122 #define kUSBPrinterClassDeviceNotOpen -9664 /*kPMInvalidIOMContext*/
123
124
125 /*
126 * Section 5.3 USB Printing Class spec
127 */
128 #define kUSBPrintingSubclass 1
129 #define kUSBPrintingProtocolNoOpen 0
130 #define kUSBPrintingProtocolUnidirectional 1
131 #define kUSBPrintingProtocolBidirectional 2
132
133 typedef IOUSBInterfaceInterface190 **printer_interface_t;
134
135 typedef struct iodevice_request_s /**** Device request ****/
136 {
137 UInt8 requestType;
138 UInt8 request;
139 UInt16 value;
140 UInt16 index;
141 UInt16 length;
142 void *buffer;
143 } iodevice_request_t;
144
145 typedef union /**** Centronics status byte ****/
146 {
147 char b;
148 struct
149 {
150 unsigned reserved0:2;
151 unsigned paperError:1;
152 unsigned select:1;
153 unsigned notError:1;
154 unsigned reserved1:3;
155 } status;
156 } centronics_status_t;
157
158 typedef struct classdriver_s /**** g.classdriver context ****/
159 {
160 IUNKNOWN_C_GUTS;
161 CFPlugInRef plugin; /* release plugin */
162 IUnknownVTbl **factory; /* Factory */
163 void *vendorReference; /* vendor class specific usage */
164 UInt32 location; /* unique location in bus topology */
165 UInt8 interfaceNumber; /* Interface number */
166 UInt16 vendorID; /* Vendor id */
167 UInt16 productID; /* Product id */
168 printer_interface_t interface; /* identify the device to IOKit */
169 UInt8 outpipe; /* mandatory bulkOut pipe */
170 UInt8 inpipe; /* optional bulkIn pipe */
171
172 /* general class requests */
173 kern_return_t (*DeviceRequest)(struct classdriver_s **printer, iodevice_request_t *iorequest, UInt16 timeout);
174 kern_return_t (*GetString)(struct classdriver_s **printer, UInt8 whichString, UInt16 language, UInt16 timeout, CFStringRef *result);
175
176 /* standard printer class requests */
177 kern_return_t (*SoftReset)(struct classdriver_s **printer, UInt16 timeout);
178 kern_return_t (*GetCentronicsStatus)(struct classdriver_s **printer, centronics_status_t *result, UInt16 timeout);
179 kern_return_t (*GetDeviceID)(struct classdriver_s **printer, CFStringRef *devid, UInt16 timeout);
180
181 /* standard bulk device requests */
182 kern_return_t (*ReadPipe)(struct classdriver_s **printer, UInt8 *buffer, UInt32 *count);
183 kern_return_t (*WritePipe)(struct classdriver_s **printer, UInt8 *buffer, UInt32 *count, Boolean eoj);
184
185 /* interface requests */
186 kern_return_t (*Open)(struct classdriver_s **printer, UInt32 location, UInt8 protocol);
187 kern_return_t (*Abort)(struct classdriver_s **printer);
188 kern_return_t (*Close)(struct classdriver_s **printer);
189
190 /* initialize and terminate */
191 kern_return_t (*Initialize)(struct classdriver_s **printer, struct classdriver_s **baseclass);
192 kern_return_t (*Terminate)(struct classdriver_s **printer);
193
194 } classdriver_t;
195
196 typedef Boolean (*iterator_callback_t)(void *refcon, io_service_t obj);
197
198 typedef struct iterator_reference_s /**** Iterator reference data */
199 {
200 iterator_callback_t callback;
201 void *userdata;
202 Boolean keepRunning;
203 } iterator_reference_t;
204
205 typedef struct globals_s
206 {
207 io_service_t printer_obj;
208 classdriver_t **classdriver;
209
210 pthread_mutex_t read_thread_mutex;
211 pthread_cond_t read_thread_cond;
212 int read_thread_stop;
213 int read_thread_done;
214
215 pthread_mutex_t readwrite_lock_mutex;
216 pthread_cond_t readwrite_lock_cond;
217 int readwrite_lock;
218
219 CFStringRef make;
220 CFStringRef model;
221 CFStringRef serial;
222 UInt32 location;
223
224 CFRunLoopTimerRef status_timer;
225
226 int print_fd; /* File descriptor to print */
227 ssize_t print_bytes; /* Print bytes read */
228
229 Boolean wait_eof;
230 int drain_output; /* Drain all pending output */
231 int bidi_flag; /* 0=unidirectional, 1=bidirectional */
232 } globals_t;
233
234
235 /*
236 * Globals...
237 */
238
239 globals_t g = { 0 }; /* Globals */
240
241
242 /*
243 * Local functions...
244 */
245
246 static Boolean find_device_cb(void *refcon, io_service_t obj);
247 static Boolean list_device_cb(void *refcon, io_service_t obj);
248 static CFStringRef cfstr_create_trim(const char *cstr);
249 static CFStringRef copy_value_for_key(CFStringRef deviceID, CFStringRef *keys);
250 static kern_return_t load_classdriver(CFStringRef driverPath, printer_interface_t intf, classdriver_t ***printerDriver);
251 static kern_return_t load_printerdriver(CFStringRef *driverBundlePath);
252 static kern_return_t registry_close();
253 static kern_return_t registry_open(CFStringRef *driverBundlePath);
254 static kern_return_t unload_classdriver();
255 static OSStatus copy_deviceid(classdriver_t **printer, CFStringRef *deviceID);
256 static void *read_thread(void *reference);
257 static void *sidechannel_thread(void *reference);
258 static void copy_deviceinfo(CFStringRef deviceIDString, CFStringRef *make, CFStringRef *model, CFStringRef *serial);
259 static void copy_devicestring(io_service_t usbInterface, CFStringRef *deviceID, UInt32 *deviceLocation);
260 static void device_added(void *userdata, io_iterator_t iterator);
261 static void get_device_id(cups_sc_status_t *status, char *data, int *datalen);
262 static void iterate_printers(iterator_callback_t callBack, void *userdata);
263 static void parse_options(const char *options, char *serial, UInt32 *location, Boolean *wait_eof);
264 static void release_deviceinfo(CFStringRef *make, CFStringRef *model, CFStringRef *serial);
265 static void setup_cfLanguage(void);
266 static void soft_reset();
267 static void status_timer_cb(CFRunLoopTimerRef timer, void *info);
268
269 #if defined(__i386__)
270 static pid_t child_pid; /* Child PID */
271 static void run_ppc_backend(int argc, char *argv[], int fd); /* Starts child backend process running as a ppc executable */
272 static void sigterm_handler(int sig); /* SIGTERM handler */
273 #endif /* __i386__ */
274
275 #ifdef PARSE_PS_ERRORS
276 static const char *next_line (const char *buffer);
277 static void parse_pserror (char *sockBuffer, int len);
278 #endif /* PARSE_PS_ERRORS */
279
280 #pragma mark -
281
282 /*
283 * 'list_devices()' - List all USB devices.
284 */
285
286 void list_devices()
287 {
288 iterate_printers(list_device_cb, NULL);
289 }
290
291
292 /*
293 * 'print_device()' - Print a file to a USB device.
294 */
295
296 int /* O - Exit status */
297 print_device(const char *uri, /* I - Device URI */
298 const char *hostname, /* I - Hostname/manufacturer */
299 const char *resource, /* I - Resource/modelname */
300 const char *options, /* I - Device options/serial number */
301 int print_fd, /* I - File descriptor to print */
302 int copies, /* I - Copies to print */
303 int argc, /* I - Number of command-line arguments (6 or 7) */
304 char *argv[]) /* I - Command-line arguments */
305 {
306 char serial[1024]; /* Serial number buffer */
307 OSStatus status; /* Function results */
308 pthread_t read_thread_id, /* Read thread */
309 sidechannel_thread_id;/* Side channel thread */
310 char print_buffer[8192], /* Print data buffer */
311 *print_ptr; /* Pointer into print data buffer */
312 UInt32 location; /* Unique location in bus topology */
313 fd_set input_set; /* Input set for select() */
314 CFStringRef driverBundlePath; /* Class driver path */
315 int countdown, /* Logging interval */
316 nfds; /* Number of file descriptors */
317 ssize_t total_bytes; /* Total bytes written */
318 UInt32 bytes; /* Bytes written */
319 struct timeval *timeout, /* Timeout pointer */
320 stimeout; /* Timeout for select() */
321 struct timespec cond_timeout; /* pthread condition timeout */
322
323 setup_cfLanguage();
324
325 parse_options(options, serial, &location, &g.wait_eof);
326
327 if (resource[0] == '/')
328 resource++;
329
330 g.print_fd = print_fd;
331 g.make = cfstr_create_trim(hostname);
332 g.model = cfstr_create_trim(resource);
333 g.serial = cfstr_create_trim(serial);
334 g.location = location;
335
336 fputs("STATE: +connecting-to-device\n", stderr);
337
338 countdown = INITIAL_LOG_INTERVAL;
339
340 do
341 {
342 if (g.printer_obj)
343 {
344 IOObjectRelease(g.printer_obj);
345 unload_classdriver(&g.classdriver);
346 g.printer_obj = 0x0;
347 g.classdriver = 0x0;
348 }
349
350 fprintf(stderr, "DEBUG: Looking for '%s %s'\n", hostname, resource);
351
352 iterate_printers(find_device_cb, NULL);
353
354 fputs("DEBUG: Opening connection\n", stderr);
355
356 driverBundlePath = NULL;
357
358 status = registry_open(&driverBundlePath);
359
360 #if defined(__i386__)
361 /*
362 * If we were unable to load the class drivers for this printer it's probably because they're ppc-only.
363 * In this case try to fork & exec this backend as a ppc executable so we can use them...
364 */
365 if (status == -2)
366 {
367 run_ppc_backend(argc, argv, print_fd);
368 /* Never returns here */
369 }
370 #endif /* __i386__ */
371
372 if (status == -2)
373 {
374 /*
375 * If we still were unable to load the class drivers for this printer log
376 * the error and stop the queue...
377 */
378
379 if (driverBundlePath == NULL || !CFStringGetCString(driverBundlePath, print_buffer, sizeof(print_buffer), kCFStringEncodingUTF8))
380 strlcpy(print_buffer, "USB class driver", sizeof(print_buffer));
381
382 fputs("STATE: +apple-missing-usbclassdriver-error\n", stderr);
383 fprintf(stderr, _("FATAL: Could not load %s\n"), print_buffer);
384
385 if (driverBundlePath)
386 CFRelease(driverBundlePath);
387
388 return CUPS_BACKEND_STOP;
389 }
390
391 if (driverBundlePath)
392 CFRelease(driverBundlePath);
393
394 if (status != noErr)
395 {
396 sleep(PRINTER_POLLING_INTERVAL);
397 countdown -= PRINTER_POLLING_INTERVAL;
398 if (countdown <= 0)
399 {
400 fprintf(stderr, _("INFO: Printer busy (status:0x%08x)\n"), (int)status);
401 countdown = SUBSEQUENT_LOG_INTERVAL; /* subsequent log entries, every 15 seconds */
402 }
403 }
404 } while (status != noErr);
405
406 fputs("STATE: -connecting-to-device\n", stderr);
407
408 /*
409 * Now that we are "connected" to the port, ignore SIGTERM so that we
410 * can finish out any page data the driver sends (e.g. to eject the
411 * current page... Only ignore SIGTERM if we are printing data from
412 * stdin (otherwise you can't cancel raw jobs...)
413 */
414
415 if (!print_fd)
416 {
417 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
418 sigset(SIGTERM, SIG_IGN);
419 #elif defined(HAVE_SIGACTION)
420 memset(&action, 0, sizeof(action));
421
422 sigemptyset(&action.sa_mask);
423 action.sa_handler = SIG_IGN;
424 sigaction(SIGTERM, &action, NULL);
425 #else
426 signal(SIGTERM, SIG_IGN);
427 #endif /* HAVE_SIGSET */
428 }
429
430 /*
431 * Start the side channel thread only if the descriptor is valid
432 * (i.e. it's not when the backend is used for auto-setup)...
433 */
434
435 pthread_mutex_init(&g.readwrite_lock_mutex, NULL);
436 pthread_cond_init(&g.readwrite_lock_cond, NULL);
437 g.readwrite_lock = 1;
438
439 FD_ZERO(&input_set);
440 FD_SET(CUPS_SC_FD, &input_set);
441
442 stimeout.tv_sec = 0;
443 stimeout.tv_usec = 0;
444
445 if ((select(CUPS_SC_FD+1, &input_set, NULL, NULL, &stimeout)) >= 0)
446 {
447 if (pthread_create(&sidechannel_thread_id, NULL, sidechannel_thread, NULL))
448 {
449 fputs(_("WARNING: Couldn't create side channel\n"), stderr);
450 return CUPS_BACKEND_STOP;
451 }
452 }
453
454 /*
455 * Get the read thread going...
456 */
457
458 g.read_thread_stop = 0;
459 g.read_thread_done = 0;
460
461 pthread_cond_init(&g.read_thread_cond, NULL);
462 pthread_mutex_init(&g.read_thread_mutex, NULL);
463
464 if (pthread_create(&read_thread_id, NULL, read_thread, NULL))
465 {
466 fputs(_("WARNING: Couldn't create read channel\n"), stderr);
467 return CUPS_BACKEND_STOP;
468 }
469
470 /*
471 * The main thread sends the print file...
472 */
473
474 g.drain_output = 0;
475 g.print_bytes = 0;
476 total_bytes = 0;
477 print_ptr = print_buffer;
478
479 while (status == noErr && copies-- > 0)
480 {
481 fputs(_("INFO: Sending data\n"), stderr);
482
483 if (print_fd != STDIN_FILENO)
484 {
485 fputs("PAGE: 1 1", stderr);
486 lseek(print_fd, 0, SEEK_SET);
487 }
488
489 while (status == noErr)
490 {
491 FD_ZERO(&input_set);
492
493 if (!g.print_bytes)
494 FD_SET(print_fd, &input_set);
495
496 /*
497 * Calculate select timeout...
498 * If we have data waiting to send timeout is 100ms.
499 * else if we're draining print_fd timeout is 0.
500 * else we're waiting forever...
501 */
502
503 if (g.print_bytes)
504 {
505 stimeout.tv_sec = 0;
506 stimeout.tv_usec = 100000; /* 100ms */
507 timeout = &stimeout;
508 }
509 else if (g.drain_output)
510 {
511 stimeout.tv_sec = 0;
512 stimeout.tv_usec = 0;
513 timeout = &stimeout;
514 }
515 else
516 timeout = NULL;
517
518 /*
519 * I/O is unlocked around select...
520 */
521
522 pthread_mutex_lock(&g.readwrite_lock_mutex);
523 g.readwrite_lock = 0;
524 pthread_cond_signal(&g.readwrite_lock_cond);
525 pthread_mutex_unlock(&g.readwrite_lock_mutex);
526
527 nfds = select(print_fd + 1, &input_set, NULL, NULL, timeout);
528
529 /*
530 * Reacquire the lock...
531 */
532
533 pthread_mutex_lock(&g.readwrite_lock_mutex);
534 while (g.readwrite_lock)
535 pthread_cond_wait(&g.readwrite_lock_cond, &g.readwrite_lock_mutex);
536 g.readwrite_lock = 1;
537 pthread_mutex_unlock(&g.readwrite_lock_mutex);
538
539 if (nfds < 0)
540 {
541 if (errno == EINTR && total_bytes == 0)
542 {
543 fputs("DEBUG: Received an interrupt before any bytes were "
544 "written, aborting!\n", stderr);
545 return (0);
546 }
547 else if (errno != EAGAIN)
548 {
549 fprintf(stderr, _("ERROR: select() returned %d\n"), (int)errno);
550 return CUPS_BACKEND_STOP;
551 }
552 }
553
554 /*
555 * If drain output has finished send a response...
556 */
557
558 if (g.drain_output && !nfds && !g.print_bytes)
559 {
560 /* Send a response... */
561 cupsSideChannelWrite(CUPS_SC_CMD_DRAIN_OUTPUT, CUPS_SC_STATUS_OK, NULL, 0, 1.0);
562 g.drain_output = 0;
563 }
564
565 /*
566 * Check if we have print data ready...
567 */
568
569 if (FD_ISSET(print_fd, &input_set))
570 {
571 g.print_bytes = read(print_fd, print_buffer, sizeof(print_buffer));
572
573 if (g.print_bytes < 0)
574 {
575 /*
576 * Read error - bail if we don't see EAGAIN or EINTR...
577 */
578
579 if (errno != EAGAIN || errno != EINTR)
580 {
581 perror("ERROR: Unable to read print data");
582 return CUPS_BACKEND_STOP;
583 }
584
585 g.print_bytes = 0;
586 }
587 else if (g.print_bytes == 0)
588 {
589 /*
590 * End of file, break out of the loop...
591 */
592
593 break;
594 }
595
596 print_ptr = print_buffer;
597
598 fprintf(stderr, "DEBUG: Read %d bytes of print data...\n",
599 (int)g.print_bytes);
600 }
601
602 if (g.print_bytes)
603 {
604 bytes = g.print_bytes;
605
606 status = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
607
608 /*
609 * Ignore timeout errors...
610 */
611
612 if (status == kIOUSBTransactionTimeout)
613 {
614 status = 0;
615 bytes = 0;
616 }
617
618 if (status || bytes < 0)
619 {
620 /*
621 * Write error - bail if we don't see an error we can retry...
622 */
623
624 OSStatus err = (*g.classdriver)->Abort(g.classdriver);
625 fprintf(stderr, _("ERROR: %ld: (canceled:%ld)\n"), (long)status, (long)err);
626 return CUPS_BACKEND_STOP;
627 }
628
629 fprintf(stderr, "DEBUG: Wrote %d bytes of print data...\n", (int)bytes);
630
631 g.print_bytes -= bytes;
632 print_ptr += bytes;
633 total_bytes += bytes;
634 }
635
636 if (print_fd != 0 && status == noErr)
637 fprintf(stderr, "DEBUG: Sending print file, %lld bytes...\n",
638 (off_t)total_bytes);
639 }
640 }
641
642 fprintf(stderr, "DEBUG: Sent %lld bytes...\n", (off_t)total_bytes);
643
644 /*
645 * Wait for the side channel thread to exit...
646 */
647
648 close(CUPS_SC_FD);
649 pthread_mutex_lock(&g.readwrite_lock_mutex);
650 g.readwrite_lock = 0;
651 pthread_cond_signal(&g.readwrite_lock_cond);
652 pthread_mutex_unlock(&g.readwrite_lock_mutex);
653
654 pthread_join(sidechannel_thread_id, NULL);
655
656 pthread_cond_destroy(&g.readwrite_lock_cond);
657 pthread_mutex_destroy(&g.readwrite_lock_mutex);
658
659 /*
660 * Signal the read thread to stop...
661 */
662
663 g.read_thread_stop = 1;
664
665 /*
666 * Give the read thread WAIT_EOF_DELAY seconds to complete all the data. If
667 * we are not signaled in that time then force the thread to exit by setting
668 * the waiteof to be false. Plese note that this relies on us using the timeout
669 * class driver.
670 */
671
672 pthread_mutex_lock(&g.read_thread_mutex);
673
674 if (!g.read_thread_done)
675 {
676 cond_timeout.tv_sec = time(NULL) + WAIT_EOF_DELAY;
677 cond_timeout.tv_nsec = 0;
678
679 if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex, &cond_timeout) != 0)
680 g.wait_eof = false;
681 }
682 pthread_mutex_unlock(&g.read_thread_mutex);
683
684 pthread_join(read_thread_id, NULL); /* wait for the read thread to return */
685
686 pthread_cond_destroy(&g.read_thread_cond);
687 pthread_mutex_destroy(&g.read_thread_mutex);
688
689 /*
690 * Close the connection and input file and general clean up...
691 */
692
693 registry_close();
694
695 if (print_fd != STDIN_FILENO)
696 close(print_fd);
697
698 if (g.make != NULL)
699 CFRelease(g.make);
700
701 if (g.model != NULL)
702 CFRelease(g.model);
703
704 if (g.serial != NULL)
705 CFRelease(g.serial);
706
707 if (g.printer_obj != 0x0)
708 IOObjectRelease(g.printer_obj);
709
710 return status;
711 }
712
713
714 /*
715 * 'read_thread()' - Thread to read the backchannel data on.
716 */
717
718 static void *read_thread(void *reference)
719 {
720 UInt8 readbuffer[512];
721 UInt32 rbytes;
722 kern_return_t readstatus;
723 struct mach_timebase_info timeBaseInfo;
724 uint64_t start,
725 delay;
726
727 /* Calculate what 250 milliSeconds are in mach absolute time...
728 */
729 mach_timebase_info(&timeBaseInfo);
730 delay = ((uint64_t)250000000 * (uint64_t)timeBaseInfo.denom) / (uint64_t)timeBaseInfo.numer;
731
732 do
733 {
734 /*
735 * Remember when we started so we can throttle the loop after the read call...
736 */
737
738 start = mach_absolute_time();
739
740 rbytes = sizeof(readbuffer);
741 readstatus = (*g.classdriver)->ReadPipe(g.classdriver, readbuffer, &rbytes);
742 if (readstatus == kIOReturnSuccess && rbytes > 0)
743 {
744 cupsBackChannelWrite((char*)readbuffer, rbytes, 1.0);
745
746 /* cntrl-d is echoed by the printer.
747 * NOTES:
748 * Xerox Phaser 6250D doesn't echo the cntrl-d.
749 * Xerox Phaser 6250D doesn't always send the product query.
750 */
751 if (g.wait_eof && readbuffer[rbytes-1] == 0x4)
752 break;
753
754 #ifdef PARSE_PS_ERRORS
755 parse_pserror(readbuffer, rbytes);
756 #endif
757 }
758
759 /*
760 * Make sure this loop executes no more than once every 250 miliseconds...
761 */
762
763 if ((readstatus != kIOReturnSuccess || rbytes == 0) && (g.wait_eof || !g.read_thread_stop))
764 mach_wait_until(start + delay);
765
766 } while (g.wait_eof || !g.read_thread_stop); /* Abort from main thread tests error here */
767
768 /*
769 * Let the main thread know that we have completed the read thread...
770 */
771
772 pthread_mutex_lock(&g.read_thread_mutex);
773 g.read_thread_done = 1;
774 pthread_cond_signal(&g.read_thread_cond);
775 pthread_mutex_unlock(&g.read_thread_mutex);
776
777 return NULL;
778 }
779
780
781 /*
782 * 'sidechannel_thread()' - Handle side-channel requests.
783 */
784
785 static void*
786 sidechannel_thread(void *reference)
787 {
788 cups_sc_command_t command; /* Request command */
789 cups_sc_status_t status; /* Request/response status */
790 char data[2048]; /* Request/response data */
791 int datalen; /* Request/response data size */
792
793 for (;;)
794 {
795 datalen = sizeof(data);
796
797 if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
798 break;
799
800 switch (command)
801 {
802 case CUPS_SC_CMD_SOFT_RESET: /* Do a soft reset */
803 soft_reset();
804 cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, NULL, 0, 1.0);
805 break;
806
807 case CUPS_SC_CMD_DRAIN_OUTPUT: /* Drain all pending output */
808 g.drain_output = 1;
809 break;
810
811 case CUPS_SC_CMD_GET_BIDI: /* Is the connection bidirectional? */
812 data[0] = g.bidi_flag;
813 cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0);
814 break;
815
816 case CUPS_SC_CMD_GET_DEVICE_ID: /* Return IEEE-1284 device ID */
817 datalen = sizeof(data);
818 get_device_id(&status, data, &datalen);
819 cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, datalen, 1.0);
820 break;
821
822 case CUPS_SC_CMD_GET_STATE: /* Return device state */
823 data[0] = CUPS_SC_STATE_ONLINE;
824 cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0);
825 break;
826
827 default:
828 cupsSideChannelWrite(command, CUPS_SC_STATUS_NOT_IMPLEMENTED,
829 NULL, 0, 1.0);
830 break;
831 }
832 }
833 return NULL;
834 }
835
836
837 #pragma mark -
838 /*
839 * 'iterate_printers()' - Iterate over all the printers.
840 */
841
842 static void iterate_printers(iterator_callback_t callBack,
843 void *userdata)
844 {
845 mach_port_t masterPort = 0x0;
846 kern_return_t kr = IOMasterPort (bootstrap_port, &masterPort);
847
848 if (kr == kIOReturnSuccess && masterPort != 0x0)
849 {
850 io_iterator_t addIterator = 0x0;
851
852 iterator_reference_t reference = { callBack, userdata, true };
853 IONotificationPortRef addNotification = IONotificationPortCreate(masterPort);
854
855 int klass = kUSBPrintingClass;
856 int subklass = kUSBPrintingSubclass;
857
858 CFNumberRef usb_klass = CFNumberCreate(NULL, kCFNumberIntType, &klass);
859 CFNumberRef usb_subklass = CFNumberCreate(NULL, kCFNumberIntType, &subklass);
860 CFMutableDictionaryRef usbPrinterMatchDictionary = IOServiceMatching(kIOUSBInterfaceClassName);
861
862 CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceClass"), usb_klass);
863 CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceSubClass"), usb_subklass);
864
865 CFRelease(usb_klass);
866 CFRelease(usb_subklass);
867
868 kr = IOServiceAddMatchingNotification(addNotification, kIOMatchedNotification, usbPrinterMatchDictionary, &device_added, &reference, &addIterator);
869 if (addIterator != 0x0)
870 {
871 device_added (&reference, addIterator);
872
873 if (reference.keepRunning)
874 {
875 CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(addNotification), kCFRunLoopDefaultMode);
876 CFRunLoopRun();
877 }
878 IOObjectRelease(addIterator);
879 }
880 mach_port_deallocate(mach_task_self(), masterPort);
881 }
882 }
883
884
885 /*
886 * 'device_added()' - Device added notifier.
887 */
888
889 static void device_added(void *userdata,
890 io_iterator_t iterator)
891 {
892 iterator_reference_t *reference = userdata;
893
894 io_service_t obj;
895 while (reference->keepRunning && (obj = IOIteratorNext(iterator)) != 0x0)
896 {
897 if (reference->callback != NULL)
898 reference->keepRunning = reference->callback(reference->userdata, obj);
899
900 IOObjectRelease(obj);
901 }
902
903 /* One last call to the call back now that we are not longer have printers left to iterate...
904 */
905 if (reference->keepRunning)
906 reference->keepRunning = reference->callback(reference->userdata, 0x0);
907
908 if (!reference->keepRunning)
909 CFRunLoopStop(CFRunLoopGetCurrent());
910 }
911
912
913 /*
914 * 'list_device_cb()' - list_device iterator callback.
915 */
916
917 static Boolean list_device_cb(void *refcon,
918 io_service_t obj)
919 {
920 Boolean keepRunning = (obj != 0x0);
921
922 if (keepRunning)
923 {
924 CFStringRef deviceIDString = NULL;
925 UInt32 deviceLocation = 0;
926
927 copy_devicestring(obj, &deviceIDString, &deviceLocation);
928 if (deviceIDString != NULL)
929 {
930 CFStringRef make = NULL, model = NULL, serial = NULL;
931 char uristr[1024], makestr[1024], modelstr[1024], serialstr[1024];
932 char optionsstr[1024], idstr[1024];
933
934 copy_deviceinfo(deviceIDString, &make, &model, &serial);
935
936 modelstr[0] = '/';
937
938 CFStringGetCString(deviceIDString, idstr, sizeof(idstr),
939 kCFStringEncodingUTF8);
940
941 if (make)
942 CFStringGetCString(make, makestr, sizeof(makestr),
943 kCFStringEncodingUTF8);
944 else
945 strcpy(makestr, "Unknown");
946
947 if (model)
948 CFStringGetCString(model, &modelstr[1], sizeof(modelstr)-1,
949 kCFStringEncodingUTF8);
950 else
951 strcpy(modelstr + 1, "Printer");
952
953 optionsstr[0] = '\0';
954 if (serial != NULL)
955 {
956 CFStringGetCString(serial, serialstr, sizeof(serialstr), kCFStringEncodingUTF8);
957 snprintf(optionsstr, sizeof(optionsstr), "?serial=%s", serialstr);
958 }
959 else if (deviceLocation != 0)
960 snprintf(optionsstr, sizeof(optionsstr), "?location=%x", (unsigned)deviceLocation);
961
962 httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
963 strncat(uristr, optionsstr, sizeof(uristr));
964
965 /*
966 * Fix common HP 1284 bug...
967 */
968
969 if (!strcasecmp(makestr, "Hewlett-Packard"))
970 strcpy(makestr, "HP");
971
972 if (!strncasecmp(modelstr + 1, "hp ", 3))
973 _cups_strcpy(modelstr + 1, modelstr + 4);
974
975 printf("direct %s \"%s %s\" \"%s %s USB\" \"%s\"\n", uristr, makestr,
976 &modelstr[1], makestr, &modelstr[1], idstr);
977
978 release_deviceinfo(&make, &model, &serial);
979 CFRelease(deviceIDString);
980 }
981 }
982
983 return keepRunning;
984 }
985
986
987 /*
988 * 'find_device_cb()' - print_device iterator callback.
989 */
990
991 static Boolean find_device_cb(void *refcon,
992 io_service_t obj)
993 {
994 Boolean keepLooking = true;
995
996 if (obj != 0x0)
997 {
998 CFStringRef idString = NULL;
999 UInt32 location = -1;
1000
1001 copy_devicestring(obj, &idString, &location);
1002 if (idString != NULL)
1003 {
1004 CFStringRef make = NULL, model = NULL, serial = NULL;
1005
1006 copy_deviceinfo(idString, &make, &model, &serial);
1007 if (CFStringCompare(make, g.make, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
1008 {
1009 if (CFStringCompare(model, g.model, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
1010 {
1011 if (g.serial != NULL && CFStringGetLength(g.serial) > 0)
1012 {
1013 if (serial != NULL && CFStringCompare(serial, g.serial, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
1014 {
1015 IOObjectRetain(obj);
1016 g.printer_obj = obj;
1017 keepLooking = false;
1018 }
1019 }
1020 else
1021 {
1022 if (g.printer_obj != 0)
1023 IOObjectRelease(g.printer_obj);
1024
1025 g.printer_obj = obj;
1026 IOObjectRetain(obj);
1027
1028 if (g.location == 0 || g.location == location)
1029 keepLooking = false;
1030 }
1031 }
1032 }
1033
1034 release_deviceinfo(&make, &model, &serial);
1035 CFRelease(idString);
1036 }
1037 }
1038 else
1039 {
1040 keepLooking = (g.printer_obj == 0);
1041 if (obj == 0x0 && keepLooking)
1042 {
1043 CFRunLoopTimerContext context = { 0, refcon, NULL, NULL, NULL };
1044 CFRunLoopTimerRef timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + 1.0, 10, 0x0, 0x0, status_timer_cb, &context);
1045 if (timer != NULL)
1046 {
1047 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
1048 g.status_timer = timer;
1049 }
1050 }
1051 }
1052
1053 if (!keepLooking && g.status_timer != NULL)
1054 {
1055 fputs("STATE: -offline-error\n", stderr);
1056 fputs(_("INFO: Printer is now on-line.\n"), stderr);
1057 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), g.status_timer, kCFRunLoopDefaultMode);
1058 CFRelease(g.status_timer);
1059 g.status_timer = NULL;
1060 }
1061
1062 return keepLooking;
1063 }
1064
1065
1066 /*
1067 * 'status_timer_cb()' - Status timer callback.
1068 */
1069
1070 static void status_timer_cb(CFRunLoopTimerRef timer,
1071 void *info)
1072 {
1073 fputs("STATE: +offline-error\n", stderr);
1074 fputs(_("INFO: Printer is currently off-line.\n"), stderr);
1075 }
1076
1077
1078 #pragma mark -
1079 /*
1080 * 'copy_deviceinfo()' - Copy strings from the 1284 device ID.
1081 */
1082
1083 static void copy_deviceinfo(CFStringRef deviceIDString,
1084 CFStringRef *make,
1085 CFStringRef *model,
1086 CFStringRef *serial)
1087 {
1088 CFStringRef modelKeys[] = { CFSTR("MDL:"), CFSTR("MODEL:"), NULL };
1089 CFStringRef makeKeys[] = { CFSTR("MFG:"), CFSTR("MANUFACTURER:"), NULL };
1090 CFStringRef serialKeys[] = { CFSTR("SN:"), CFSTR("SERN:"), NULL };
1091
1092 if (make != NULL)
1093 *make = copy_value_for_key(deviceIDString, makeKeys);
1094 if (model != NULL)
1095 *model = copy_value_for_key(deviceIDString, modelKeys);
1096 if (serial != NULL)
1097 *serial = copy_value_for_key(deviceIDString, serialKeys);
1098 }
1099
1100
1101 /*
1102 * 'release_deviceinfo()' - Release deviceinfo strings.
1103 */
1104
1105 static void release_deviceinfo(CFStringRef *make,
1106 CFStringRef *model,
1107 CFStringRef *serial)
1108 {
1109 if (make != NULL && *make != NULL)
1110 {
1111 CFRelease(*make);
1112 *make = NULL;
1113 }
1114
1115 if (model != NULL && *model != NULL)
1116 {
1117 CFRelease(*model);
1118 *model = NULL;
1119 }
1120
1121 if (serial != NULL && *serial != NULL)
1122 {
1123 CFRelease(*serial);
1124 *serial = NULL;
1125 }
1126 }
1127
1128
1129 #pragma mark -
1130 /*
1131 * 'load_classdriver()' - Load a classdriver.
1132 */
1133
1134 static kern_return_t load_classdriver(CFStringRef driverPath,
1135 printer_interface_t intf,
1136 classdriver_t ***printerDriver)
1137 {
1138 kern_return_t kr = kUSBPrinterClassDeviceNotOpen;
1139 classdriver_t **driver = NULL;
1140 CFStringRef bundle = (driverPath == NULL ? kUSBGenericTOPrinterClassDriver : driverPath);
1141
1142 if (bundle != NULL)
1143 {
1144 CFURLRef url = CFURLCreateWithFileSystemPath(NULL, bundle, kCFURLPOSIXPathStyle, true);
1145 CFPlugInRef plugin = (url != NULL ? CFPlugInCreate(NULL, url) : NULL);
1146
1147 if (url != NULL)
1148 CFRelease(url);
1149
1150 if (plugin != NULL)
1151 {
1152 CFArrayRef factories = CFPlugInFindFactoriesForPlugInTypeInPlugIn(kUSBPrinterClassTypeID, plugin);
1153 if (factories != NULL && CFArrayGetCount(factories) > 0)
1154 {
1155 CFUUIDRef factoryID = CFArrayGetValueAtIndex(factories, 0);
1156 IUnknownVTbl **iunknown = CFPlugInInstanceCreate(NULL, factoryID, kUSBPrinterClassTypeID);
1157 if (iunknown != NULL)
1158 {
1159 kr = (*iunknown)->QueryInterface(iunknown, CFUUIDGetUUIDBytes(kUSBPrinterClassInterfaceID), (LPVOID *)&driver);
1160 if (kr == kIOReturnSuccess && driver != NULL)
1161 {
1162 classdriver_t **genericDriver = NULL;
1163 if (driverPath != NULL && CFStringCompare(driverPath, kUSBGenericTOPrinterClassDriver, 0) != kCFCompareEqualTo)
1164 kr = load_classdriver(NULL, intf, &genericDriver);
1165
1166 if (kr == kIOReturnSuccess)
1167 {
1168 (*driver)->interface = intf;
1169 (*driver)->Initialize(driver, genericDriver);
1170
1171 (*driver)->plugin = plugin;
1172 (*driver)->interface = intf;
1173 *printerDriver = driver;
1174 }
1175 }
1176 (*iunknown)->Release(iunknown);
1177 }
1178 CFRelease(factories);
1179 }
1180 }
1181 }
1182
1183 #ifdef DEBUG
1184 char bundlestr[1024];
1185 CFStringGetCString(bundle, bundlestr, sizeof(bundlestr), kCFStringEncodingUTF8);
1186 fprintf(stderr, "DEBUG: load_classdriver(%s) (kr:0x%08x)\n", bundlestr, (int)kr);
1187 #endif /* DEBUG */
1188
1189 return kr;
1190 }
1191
1192
1193 /*
1194 * 'unload_classdriver()' - Unload a classdriver.
1195 */
1196
1197 static kern_return_t unload_classdriver(classdriver_t ***classdriver)
1198 {
1199 if (*classdriver != NULL)
1200 {
1201 (**classdriver)->Release(*classdriver);
1202 *classdriver = NULL;
1203 }
1204
1205 return kIOReturnSuccess;
1206 }
1207
1208
1209 /*
1210 * 'load_printerdriver()' - Load vendor's classdriver.
1211 *
1212 * If driverBundlePath is not NULL on return it is the callers responsbility to release it!
1213 */
1214
1215 static kern_return_t load_printerdriver(CFStringRef *driverBundlePath)
1216 {
1217 IOCFPlugInInterface **iodev = NULL;
1218 SInt32 score;
1219 kern_return_t kr;
1220 printer_interface_t intf;
1221 HRESULT res;
1222
1223 kr = IOCreatePlugInInterfaceForService(g.printer_obj, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
1224 if (kr == kIOReturnSuccess)
1225 {
1226 if ((res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &intf)) == noErr)
1227 {
1228 *driverBundlePath = IORegistryEntryCreateCFProperty(g.printer_obj, kUSBClassDriverProperty, NULL, kNilOptions);
1229
1230 kr = load_classdriver(*driverBundlePath, intf, &g.classdriver);
1231
1232 if (kr != kIOReturnSuccess)
1233 (*intf)->Release(intf);
1234 }
1235 IODestroyPlugInInterface(iodev);
1236 }
1237 return kr;
1238 }
1239
1240
1241 /*
1242 * 'registry_open()' - Open a connection to the printer.
1243 */
1244
1245 static kern_return_t registry_open(CFStringRef *driverBundlePath)
1246 {
1247 g.bidi_flag = 0; /* 0=unidirectional */
1248
1249 kern_return_t kr = load_printerdriver(driverBundlePath);
1250 if (kr != kIOReturnSuccess)
1251 kr = -2;
1252
1253 if (g.classdriver != NULL)
1254 {
1255 kr = (*g.classdriver)->Open(g.classdriver, g.location, kUSBPrintingProtocolBidirectional);
1256 if (kr != kIOReturnSuccess || (*g.classdriver)->interface == NULL)
1257 {
1258 kr = (*g.classdriver)->Open(g.classdriver, g.location, kUSBPrintingProtocolUnidirectional);
1259 if (kr == kIOReturnSuccess)
1260 {
1261 if ((*g.classdriver)->interface == NULL)
1262 {
1263 (*g.classdriver)->Close(g.classdriver);
1264 kr = -1;
1265 }
1266 }
1267 }
1268 else
1269 g.bidi_flag = 1; /* 1=bidirectional */
1270 }
1271
1272 if (kr != kIOReturnSuccess)
1273 unload_classdriver(&g.classdriver);
1274
1275 return kr;
1276 }
1277
1278
1279 /*
1280 * 'registry_close()' - Close the connection to the printer.
1281 */
1282
1283 static kern_return_t registry_close()
1284 {
1285 if (g.classdriver != NULL)
1286 (*g.classdriver)->Close(g.classdriver);
1287
1288 unload_classdriver(&g.classdriver);
1289 return kIOReturnSuccess;
1290 }
1291
1292
1293 /*
1294 * 'copy_deviceid()' - Copy the 1284 device id string.
1295 */
1296
1297 static OSStatus copy_deviceid(classdriver_t **classdriver,
1298 CFStringRef *deviceID)
1299 {
1300 CFStringRef devID = NULL,
1301
1302 deviceMake = NULL,
1303 deviceModel = NULL,
1304 deviceSerial = NULL;
1305
1306 OSStatus err = (*classdriver)->GetDeviceID(classdriver, &devID, DEFAULT_TIMEOUT);
1307
1308 copy_deviceinfo(devID, &deviceMake, &deviceModel, &deviceSerial);
1309
1310 if (deviceMake == NULL || deviceModel == NULL || deviceSerial == NULL)
1311 {
1312 IOUSBDeviceDescriptor desc;
1313 iodevice_request_t request;
1314
1315 request.requestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
1316 request.request = kUSBRqGetDescriptor;
1317 request.value = (kUSBDeviceDesc << 8) | 0;
1318 request.index = 0;
1319 request.length = sizeof(desc);
1320 request.buffer = &desc;
1321 err = (*classdriver)->DeviceRequest(classdriver, &request, DEFAULT_TIMEOUT);
1322 if (err == kIOReturnSuccess)
1323 {
1324 CFMutableStringRef newDevID = CFStringCreateMutable(NULL, 0);
1325
1326 if (deviceMake == NULL)
1327 {
1328 CFStringRef data = NULL;
1329 err = (*classdriver)->GetString(classdriver, desc.iManufacturer, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &data);
1330 if (data != NULL)
1331 {
1332 CFStringAppendFormat(newDevID, NULL, CFSTR("MFG:%@;"), data);
1333 CFRelease(data);
1334 }
1335 }
1336
1337 if (deviceModel == NULL)
1338 {
1339 CFStringRef data = NULL;
1340 err = (*classdriver)->GetString(classdriver, desc.iProduct, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &data);
1341 if (data != NULL)
1342 {
1343 CFStringAppendFormat(newDevID, NULL, CFSTR("MDL:%@;"), data);
1344 CFRelease(data);
1345 }
1346 }
1347
1348 if (deviceSerial == NULL && desc.iSerialNumber != 0)
1349 {
1350 CFStringRef data = NULL;
1351 err = (*classdriver)->GetString(classdriver, desc.iSerialNumber, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &data);
1352 if (data != NULL)
1353 {
1354 CFStringAppendFormat(newDevID, NULL, CFSTR("SERN:%@;"), data);
1355 CFRelease(data);
1356 }
1357 }
1358
1359 if (devID != NULL)
1360 {
1361 CFStringAppend(newDevID, devID);
1362 CFRelease(devID);
1363 }
1364
1365 *deviceID = newDevID;
1366 }
1367 }
1368 else
1369 {
1370 *deviceID = devID;
1371 }
1372 release_deviceinfo(&deviceMake, &deviceModel, &deviceSerial);
1373
1374 return err;
1375 }
1376
1377
1378 /*
1379 * 'copy_devicestring()' - Copy the 1284 device id string.
1380 */
1381
1382 static void copy_devicestring(io_service_t usbInterface,
1383 CFStringRef *deviceID,
1384 UInt32 *deviceLocation)
1385 {
1386 IOCFPlugInInterface **iodev = NULL;
1387 SInt32 score;
1388 kern_return_t kr;
1389 printer_interface_t intf;
1390 HRESULT res;
1391 classdriver_t **klassDriver = NULL;
1392 CFStringRef driverBundlePath;
1393
1394 if ((kr = IOCreatePlugInInterfaceForService(usbInterface,
1395 kIOUSBInterfaceUserClientTypeID,
1396 kIOCFPlugInInterfaceID,
1397 &iodev, &score)) == kIOReturnSuccess)
1398 {
1399 if ((res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *)
1400 &intf)) == noErr)
1401 {
1402 (*intf)->GetLocationID(intf, deviceLocation);
1403
1404 driverBundlePath = IORegistryEntryCreateCFProperty(usbInterface,
1405 kUSBClassDriverProperty,
1406 NULL, kNilOptions);
1407
1408 kr = load_classdriver(driverBundlePath, intf, &klassDriver);
1409
1410 if (kr != kIOReturnSuccess && driverBundlePath != NULL)
1411 kr = load_classdriver(NULL, intf, &klassDriver);
1412
1413 if (kr == kIOReturnSuccess && klassDriver != NULL)
1414 kr = copy_deviceid(klassDriver, deviceID);
1415
1416 unload_classdriver(&klassDriver);
1417
1418 if (driverBundlePath != NULL)
1419 CFRelease(driverBundlePath);
1420
1421 /* (*intf)->Release(intf); */
1422 }
1423 IODestroyPlugInInterface(iodev);
1424 }
1425 }
1426
1427
1428 #pragma mark -
1429 /*
1430 * 'copy_value_for_key()' - Copy value string associated with a key.
1431 */
1432
1433 static CFStringRef copy_value_for_key(CFStringRef deviceID,
1434 CFStringRef *keys)
1435 {
1436 CFStringRef value = NULL;
1437 CFArrayRef kvPairs = deviceID != NULL ? CFStringCreateArrayBySeparatingStrings(NULL, deviceID, CFSTR(";")) : NULL;
1438 CFIndex max = kvPairs != NULL ? CFArrayGetCount(kvPairs) : 0;
1439 CFIndex idx = 0;
1440
1441 while (idx < max && value == NULL)
1442 {
1443 CFStringRef kvpair = CFArrayGetValueAtIndex(kvPairs, idx);
1444 CFIndex idxx = 0;
1445 while (keys[idxx] != NULL && value == NULL)
1446 {
1447 CFRange range = CFStringFind(kvpair, keys[idxx], kCFCompareCaseInsensitive);
1448 if (range.length != -1)
1449 {
1450 if (range.location != 0)
1451 {
1452 CFMutableStringRef theString = CFStringCreateMutableCopy(NULL, 0, kvpair);
1453 CFStringTrimWhitespace(theString);
1454 range = CFStringFind(theString, keys[idxx], kCFCompareCaseInsensitive);
1455 if (range.location == 0)
1456 value = CFStringCreateWithSubstring(NULL, theString, CFRangeMake(range.length, CFStringGetLength(theString) - range.length));
1457
1458 CFRelease(theString);
1459 }
1460 else
1461 {
1462 CFStringRef theString = CFStringCreateWithSubstring(NULL, kvpair, CFRangeMake(range.length, CFStringGetLength(kvpair) - range.length));
1463 CFMutableStringRef theString2 = CFStringCreateMutableCopy(NULL, 0, theString);
1464 CFRelease(theString);
1465
1466 CFStringTrimWhitespace(theString2);
1467 value = theString2;
1468 }
1469 }
1470 idxx++;
1471 }
1472 idx++;
1473 }
1474
1475 if (kvPairs != NULL)
1476 CFRelease(kvPairs);
1477 return value;
1478 }
1479
1480
1481 /*
1482 * 'cfstr_create_trim()' - Create CFString and trim whitespace characters.
1483 */
1484
1485 CFStringRef cfstr_create_trim(const char *cstr)
1486 {
1487 CFStringRef cfstr;
1488 CFMutableStringRef cfmutablestr = NULL;
1489
1490 if ((cfstr = CFStringCreateWithCString(NULL, cstr, kCFStringEncodingUTF8)) != NULL)
1491 {
1492 if ((cfmutablestr = CFStringCreateMutableCopy(NULL, 1024, cfstr)) != NULL)
1493 CFStringTrimWhitespace(cfmutablestr);
1494
1495 CFRelease(cfstr);
1496 }
1497 return (CFStringRef) cfmutablestr;
1498 }
1499
1500
1501 #pragma mark -
1502 /*
1503 * 'parse_options()' - Parse uri options.
1504 */
1505
1506 static void parse_options(const char *options,
1507 char *serial,
1508 UInt32 *location,
1509 Boolean *wait_eof)
1510 {
1511 char *serialnumber; /* ?serial=<serial> or ?location=<location> */
1512 char optionName[255], /* Name of option */
1513 value[255], /* Value of option */
1514 *ptr; /* Pointer into name or value */
1515
1516 if (serial)
1517 *serial = '\0';
1518 if (location)
1519 *location = 0;
1520
1521 if (!options)
1522 return;
1523
1524 serialnumber = NULL;
1525
1526 while (*options != '\0')
1527 {
1528 /* Get the name... */
1529 for (ptr = optionName; *options && *options != '=' && *options != '+';)
1530 *ptr++ = *options++;
1531
1532 *ptr = '\0';
1533 value[0] = '\0';
1534
1535 if (*options == '=')
1536 {
1537 /* Get the value... */
1538 options ++;
1539
1540 for (ptr = value; *options && *options != '+';)
1541 *ptr++ = *options++;
1542
1543 *ptr = '\0';
1544
1545 if (*options == '+')
1546 options ++;
1547 }
1548 else if (*options == '+')
1549 options ++;
1550
1551 /*
1552 * Process the option...
1553 */
1554 if (strcasecmp(optionName, "waiteof") == 0)
1555 {
1556 if (strcasecmp(value, "on") == 0 ||
1557 strcasecmp(value, "yes") == 0 ||
1558 strcasecmp(value, "true") == 0)
1559 *wait_eof = true;
1560 else if (strcasecmp(value, "off") == 0 ||
1561 strcasecmp(value, "no") == 0 ||
1562 strcasecmp(value, "false") == 0)
1563 *wait_eof = false;
1564 else
1565 fprintf(stderr, _("WARNING: Boolean expected for waiteof option \"%s\"\n"), value);
1566 }
1567 else if (strcasecmp(optionName, "serial") == 0)
1568 {
1569 strcpy(serial, value);
1570 serialnumber = serial;
1571 }
1572 else if (strcasecmp(optionName, "location") == 0 && location)
1573 *location = strtol(value, NULL, 16);
1574 }
1575
1576 return;
1577 }
1578
1579
1580 /*!
1581 * @function setup_cfLanguage
1582 * @abstract Convert the contents of the CUPS 'LANG' environment
1583 * variable into a one element CF array of languages.
1584 *
1585 * @discussion Each submitted job comes with a natural language. CUPS passes
1586 * that language in an environment variable. We take that language
1587 * and jam it into the AppleLanguages array so that CF will use
1588 * it when reading localized resources. We need to do this before
1589 * any CF code reads and caches the languages array, so this function
1590 * should be called early in main()
1591 */
1592 static void setup_cfLanguage(void)
1593 {
1594 CFStringRef lang[1] = {NULL};
1595 CFArrayRef langArray = NULL;
1596 const char *requestedLang = NULL;
1597
1598 requestedLang = getenv("LANG");
1599 if (requestedLang != NULL)
1600 {
1601 lang[0] = CFStringCreateWithCString(kCFAllocatorDefault, requestedLang, kCFStringEncodingUTF8);
1602 langArray = CFArrayCreate(kCFAllocatorDefault, (const void **)lang, sizeof(lang) / sizeof(lang[0]), &kCFTypeArrayCallBacks);
1603
1604 CFPreferencesSetAppValue(CFSTR("AppleLanguages"), langArray, kCFPreferencesCurrentApplication);
1605 DEBUG_printf((stderr, "DEBUG: usb: AppleLanguages = \"%s\"\n", requestedLang));
1606
1607 CFRelease(lang[0]);
1608 CFRelease(langArray);
1609 }
1610 else
1611 fputs("DEBUG: usb: LANG environment variable missing.\n", stderr);
1612 }
1613
1614 #pragma mark -
1615 #if defined(__i386__)
1616 /*!
1617 * @function run_ppc_backend
1618 *
1619 * @abstract Starts child backend process running as a ppc executable.
1620 *
1621 * @result Never returns; always calls exit().
1622 *
1623 * @discussion
1624 */
1625 static void run_ppc_backend(int argc,
1626 char *argv[],
1627 int fd)
1628 {
1629 int i;
1630 int exitstatus = 0;
1631 int childstatus;
1632 pid_t waitpid_status;
1633 char *my_argv[32];
1634 char *usb_ppc_status;
1635
1636 /*
1637 * If we're running as i386 and couldn't load the class driver (because they'it's
1638 * ppc-only) then try to re-exec ourselves in ppc mode to try again. If we don't have
1639 * a ppc architecture we may be running i386 again so guard against this by setting
1640 * and testing an environment variable...
1641 */
1642 usb_ppc_status = getenv("USB_PPC_STATUS");
1643
1644 if (usb_ppc_status == NULL)
1645 {
1646 /* Catch SIGTERM if we are _not_ printing data from
1647 * stdin (otherwise you can't cancel raw jobs...)
1648 */
1649
1650 if (fd != 0)
1651 {
1652 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1653 sigset(SIGTERM, sigterm_handler);
1654 #elif defined(HAVE_SIGACTION)
1655 struct sigaction action; /* Actions for POSIX signals */
1656 memset(&action, 0, sizeof(action));
1657 sigaddset(&action.sa_mask, SIGTERM);
1658 action.sa_handler = sigterm_handler;
1659 sigaction(SIGTERM, &action, NULL);
1660 #else
1661 signal(SIGTERM, sigterm_handler);
1662 #endif /* HAVE_SIGSET */
1663 }
1664
1665 if ((child_pid = fork()) == 0)
1666 {
1667 /* Child comes here. */
1668 setenv("USB_PPC_STATUS", "1", false);
1669
1670 /* Tell the kernel we want the next exec call to favor the ppc architecture... */
1671 int mib[] = { CTL_KERN, KERN_AFFINITY, 1, 1 };
1672 int namelen = 4;
1673 sysctl(mib, namelen, NULL, NULL, NULL, 0);
1674
1675 /* Set up the arguments and call exec... */
1676 for (i = 0; i < argc && i < (sizeof(my_argv)/sizeof(my_argv[0])) - 1; i++)
1677 my_argv[i] = argv[i];
1678
1679 my_argv[i] = NULL;
1680
1681 execv("/usr/libexec/cups/backend/usb", my_argv);
1682
1683 fprintf(stderr, "DEBUG: execv: %s\n", strerror(errno));
1684 exitstatus = errno;
1685 }
1686 else if (child_pid > 0)
1687 {
1688 /* Parent comes here.
1689 *
1690 * Close the fds we won't be using then wait for the child backend to exit.
1691 */
1692 close(fd);
1693 close(1);
1694
1695 fprintf(stderr, "DEBUG: Started usb(ppc) backend (PID %d)\n", (int)child_pid);
1696
1697 while ((waitpid_status = waitpid(child_pid, &childstatus, 0)) == (pid_t)-1 && errno == EINTR)
1698 usleep(1000);
1699
1700 if (WIFSIGNALED(childstatus))
1701 {
1702 exitstatus = WTERMSIG(childstatus);
1703 fprintf(stderr, "DEBUG: usb(ppc) backend %d crashed on signal %d!\n", child_pid, exitstatus);
1704 }
1705 else
1706 {
1707 if ((exitstatus = WEXITSTATUS(childstatus)) != 0)
1708 fprintf(stderr, "DEBUG: usb(ppc) backend %d stopped with status %d!\n", child_pid, exitstatus);
1709 else
1710 fprintf(stderr, "DEBUG: PID %d exited with no errors\n", child_pid);
1711 }
1712 }
1713 else
1714 {
1715 /* fork() error */
1716 fprintf(stderr, "DEBUG: fork: %s\n", strerror(errno));
1717 exitstatus = errno;
1718 }
1719 }
1720 else
1721 {
1722 fputs("DEBUG: usb child running i386 again\n", stderr);
1723 exitstatus = ENOENT;
1724 }
1725
1726 exit(exitstatus);
1727 }
1728
1729 /*
1730 * 'sigterm_handler()' - SIGTERM handler.
1731 */
1732
1733 static void sigterm_handler(int sig)
1734 {
1735 /* If we started a child process pass the signal on to it...
1736 */
1737 if (child_pid)
1738 kill(child_pid, sig);
1739
1740 exit(1);
1741 }
1742
1743 #endif /* __i386__ */
1744
1745
1746 #ifdef PARSE_PS_ERRORS
1747 /*
1748 * 'next_line()' - Find the next line in a buffer.
1749 */
1750
1751 static const char *next_line (const char *buffer)
1752 {
1753 const char *cptr, *lptr = NULL;
1754
1755 for (cptr = buffer; *cptr && lptr == NULL; cptr++)
1756 if (*cptr == '\n' || *cptr == '\r')
1757 lptr = cptr;
1758 return lptr;
1759 }
1760
1761
1762 /*
1763 * 'parse_pserror()' - Scan the backchannel data for postscript errors.
1764 */
1765
1766 static void parse_pserror(char *sockBuffer,
1767 int len)
1768 {
1769 static char gErrorBuffer[1024] = "";
1770 static char *gErrorBufferPtr = gErrorBuffer;
1771 static char *gErrorBufferEndPtr = gErrorBuffer + sizeof(gErrorBuffer);
1772
1773 char *pCommentBegin, *pCommentEnd, *pLineEnd;
1774 char *logLevel;
1775 char logstr[1024];
1776 int logstrlen;
1777
1778 if (gErrorBufferPtr + len > gErrorBufferEndPtr - 1)
1779 gErrorBufferPtr = gErrorBuffer;
1780 if (len > sizeof(gErrorBuffer) - 1)
1781 len = sizeof(gErrorBuffer) - 1;
1782
1783 memcpy(gErrorBufferPtr, (const void *)sockBuffer, len);
1784 gErrorBufferPtr += len;
1785 *(gErrorBufferPtr + 1) = '\0';
1786
1787 pLineEnd = (char *)next_line((const char *)gErrorBuffer);
1788 while (pLineEnd != NULL)
1789 {
1790 *pLineEnd++ = '\0';
1791
1792 pCommentBegin = strstr(gErrorBuffer,"%%[");
1793 pCommentEnd = strstr(gErrorBuffer, "]%%");
1794 if (pCommentBegin != gErrorBuffer && pCommentEnd != NULL)
1795 {
1796 pCommentEnd += 3; /* Skip past "]%%" */
1797 *pCommentEnd = '\0'; /* There's always room for the nul */
1798
1799 if (strncasecmp(pCommentBegin, "%%[ Error:", 10) == 0)
1800 logLevel = "DEBUG";
1801 else if (strncasecmp(pCommentBegin, "%%[ Flushing", 12) == 0)
1802 logLevel = "DEBUG";
1803 else
1804 logLevel = "INFO";
1805
1806 if ((logstrlen = snprintf(logstr, sizeof(logstr), "%s: %s\n", logLevel, pCommentBegin)) >= sizeof(logstr))
1807 {
1808 /* If the string was trucnated make sure it has a linefeed before the nul */
1809 logstrlen = sizeof(logstr) - 1;
1810 logstr[logstrlen - 1] = '\n';
1811 }
1812 write(STDERR_FILENO, logstr, logstrlen);
1813 }
1814
1815 /* move everything over... */
1816 strcpy(gErrorBuffer, pLineEnd);
1817 gErrorBufferPtr = gErrorBuffer;
1818 pLineEnd = (char *)next_line((const char *)gErrorBuffer);
1819 }
1820 }
1821 #endif /* PARSE_PS_ERRORS */
1822
1823
1824 /*
1825 * 'soft_reset'
1826 */
1827
1828 static void soft_reset()
1829 {
1830 fd_set input_set; /* Input set for select() */
1831 struct timeval stimeout; /* Timeout for select() */
1832 char buffer[2048]; /* Buffer */
1833 struct timespec cond_timeout; /* pthread condition timeout */
1834
1835 /*
1836 * Send an abort once a second until the I/O lock is released by the main thread...
1837 */
1838
1839 pthread_mutex_lock(&g.readwrite_lock_mutex);
1840 while (g.readwrite_lock)
1841 {
1842 (*g.classdriver)->Abort(g.classdriver);
1843
1844 cond_timeout.tv_sec = time(NULL) + 1;
1845 cond_timeout.tv_nsec = 0;
1846
1847 pthread_cond_timedwait(&g.readwrite_lock_cond, &g.readwrite_lock_mutex, &cond_timeout);
1848 }
1849
1850 g.readwrite_lock = 1;
1851 pthread_mutex_unlock(&g.readwrite_lock_mutex);
1852
1853 /*
1854 * Flush bytes waiting on print_fd...
1855 */
1856
1857 g.print_bytes = 0;
1858
1859 FD_ZERO(&input_set);
1860 FD_SET(g.print_fd, &input_set);
1861
1862 stimeout.tv_sec = 0;
1863 stimeout.tv_usec = 0;
1864
1865 while (select(g.print_fd+1, &input_set, NULL, NULL, &stimeout) > 0)
1866 if (read(g.print_fd, buffer, sizeof(buffer)) <= 0)
1867 break;
1868
1869 /*
1870 * Send the reset...
1871 */
1872
1873 (*g.classdriver)->SoftReset(g.classdriver, 0);
1874
1875 /*
1876 * Release the I/O lock...
1877 */
1878
1879 pthread_mutex_lock(&g.readwrite_lock_mutex);
1880 g.readwrite_lock = 0;
1881 pthread_cond_signal(&g.readwrite_lock_cond);
1882 pthread_mutex_unlock(&g.readwrite_lock_mutex);
1883 }
1884
1885
1886 /*
1887 * 'get_device_id()' - Return IEEE-1284 device ID.
1888 */
1889
1890 static void get_device_id(cups_sc_status_t *status,
1891 char *data,
1892 int *datalen)
1893 {
1894 UInt32 deviceLocation = 0;
1895 CFStringRef deviceIDString = NULL;
1896
1897 /* GetDeviceID */
1898 copy_devicestring(g.printer_obj, &deviceIDString, &deviceLocation);
1899 if (deviceIDString)
1900 {
1901 CFStringGetCString(deviceIDString, data, *datalen, kCFStringEncodingUTF8);
1902 *datalen = strlen(data);
1903 CFRelease(deviceIDString);
1904 }
1905 *status = CUPS_SC_STATUS_OK;
1906 }
1907
1908
1909 /*
1910 * End of "$Id: usb-darwin.c 6591 2007-06-21 20:35:28Z mike $".
1911 */