/*
- * "$Id$"
+ * USB backend for macOS.
*
- * Copyright 2005-2013 Apple Inc. All rights reserved.
+ * Copyright © 2005-2021 Apple Inc. All rights reserved.
*
* IMPORTANT: This Apple software is supplied to you by Apple Computer,
* Inc. ("Apple") in consideration of your agreement to the following
#include <cups/file-private.h>
#include <cups/sidechannel.h>
#include <cups/language-private.h>
+#include <cups/ppd-private.h>
#include "backend-private.h"
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <libproc.h>
-
+#include <asl.h>
#include <spawn.h>
#include <pthread.h>
+/*
+ * Include necessary headers.
+ */
+
extern char **environ;
#define WAIT_SIDE_DELAY 3
#define DEFAULT_TIMEOUT 5000L
-#define USB_INTERFACE_KIND CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID190)
+#define USB_INTERFACE_KIND CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID245)
#define kUSBLanguageEnglish 0x409
#define PRINTER_POLLING_INTERVAL 5 /* seconds */
#define kUSBPrintingProtocolNoOpen 0
#define kUSBPrintingProtocolUnidirectional 1
#define kUSBPrintingProtocolBidirectional 2
+#define kUSBPrintingProtocolIPP 4
-typedef IOUSBInterfaceInterface190 **printer_interface_t;
+typedef IOUSBInterfaceInterface245 **printer_interface_t;
typedef struct iodevice_request_s /**** Device request ****/
{
} classdriver_t;
-typedef Boolean (*iterator_callback_t)(void *refcon, io_service_t obj);
+typedef Boolean (*iterator_callback_t)(io_service_t obj, printer_interface_t printerIntf, void *refcon);
typedef struct iterator_reference_s /**** Iterator reference data */
{
CFStringRef serial;
UInt32 location;
UInt8 interfaceNum;
+ UInt8 alternateSetting;
+ UInt8 interfaceProtocol;
CFRunLoopTimerRef status_timer;
ssize_t debug_bytes; /* Current bytes to read */
#endif /* DEBUG_WRITES */
+ Boolean use_generic_class_driver;
Boolean wait_eof;
int drain_output; /* Drain all pending output */
int bidi_flag; /* 0=unidirectional, 1=bidirectional */
* Local functions...
*/
-static Boolean find_device_cb(void *refcon, io_service_t obj);
-static Boolean list_device_cb(void *refcon, io_service_t obj);
+static Boolean list_device_cb(io_service_t obj, printer_interface_t printerIntf, void *refcon);
+static Boolean find_device_cb(io_service_t obj, printer_interface_t printerIntf, void *refcon);
+
static CFStringRef cfstr_create_trim(const char *cstr);
static CFStringRef copy_value_for_key(CFStringRef deviceID, CFStringRef *keys);
static kern_return_t load_classdriver(CFStringRef driverPath, printer_interface_t interface, classdriver_t ***printerDriver);
static kern_return_t registry_close(void);
static kern_return_t registry_open(CFStringRef *driverBundlePath);
static kern_return_t unload_classdriver(classdriver_t ***classdriver);
-static OSStatus copy_deviceid(classdriver_t **printer, CFStringRef *deviceID);
+
static void *read_thread(void *reference);
static void *sidechannel_thread(void *reference);
-static void copy_deviceinfo(CFStringRef deviceIDString, CFStringRef *make, CFStringRef *model, CFStringRef *serial);
-static void copy_devicestring(io_service_t usbInterface, CFStringRef *deviceID, UInt32 *deviceLocation, UInt8 *interfaceNum);
static void device_added(void *userdata, io_iterator_t iterator);
static void get_device_id(cups_sc_status_t *status, char *data, int *datalen);
static void iterate_printers(iterator_callback_t callBack, void *userdata);
static void parse_options(char *options, char *serial, int serial_size, UInt32 *location, Boolean *wait_eof);
-static void release_deviceinfo(CFStringRef *make, CFStringRef *model, CFStringRef *serial);
static void setup_cfLanguage(void);
static void soft_reset(void);
static void status_timer_cb(CFRunLoopTimerRef timer, void *info);
+#define IS_64BIT 1
+#define IS_NOT_64BIT 0
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__arm64e__)
static pid_t child_pid; /* Child PID */
-static void run_legacy_backend(int argc, char *argv[], int fd); /* Starts child backend process running as a ppc executable */
-#endif /* __i386__ || __x86_64__ */
-static void sigterm_handler(int sig); /* SIGTERM handler */
-static void sigquit_handler(int sig, siginfo_t *si, void *unused);
+static void run_legacy_backend(int argc, char *argv[], int fd) _CUPS_NORETURN; /* Starts child backend process running as a x86_64 executable */
+static void sigterm_handler(int sig); /* SIGTERM handler */
+#endif /* __arm64e__ */
+static void sigquit_handler(int sig, siginfo_t *si, void *unused) _CUPS_NORETURN;
#ifdef PARSE_PS_ERRORS
static const char *next_line (const char *buffer);
static void parse_pserror (char *sockBuffer, int len);
#endif /* PARSE_PS_ERRORS */
+static printer_interface_t usb_printer_interface_interface(io_service_t usbClass);
+
+static CFStringRef copy_printer_interface_deviceid(printer_interface_t printer, UInt8 alternateSetting);
+static CFStringRef copy_printer_interface_indexed_description(printer_interface_t printer, UInt8 index, UInt16 language);
+static CFStringRef deviceIDCopyManufacturer(CFStringRef deviceID);
+static CFStringRef deviceIDCopyModel(CFStringRef deviceID);
+static CFStringRef deviceIDCopySerialNumber(CFStringRef deviceID);
+
#pragma mark -
/*
g.printer_obj = 0x0;
g.classdriver = 0x0;
}
-
fprintf(stderr, "DEBUG: Looking for '%s %s'\n", hostname, resource);
- iterate_printers(find_device_cb, NULL);
+ do
+ {
+ iterate_printers(find_device_cb, NULL);
+ if (g.printer_obj != 0x0)
+ break;
+
+ _cupsLangPrintFilter(stderr, "INFO", _("Waiting for printer to become available."));
+ sleep(5);
+ } while (true);
fputs("DEBUG: Opening connection\n", stderr);
status = registry_open(&driverBundlePath);
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__arm64e__)
/*
* If we were unable to load the class drivers for this printer it's
- * probably because they're ppc or i386. In this case try to run this
- * backend as i386 or ppc executables so we can use them...
+ * probably because they're x86_64 (or older). In this case try to run this
+ * backend as x86_64 so we can use them...
*/
if (status == -2)
{
run_legacy_backend(argc, argv, print_fd);
/* Never returns here */
}
-#endif /* __i386__ || __x86_64__ */
+#endif /* __arm64e__ */
if (status == -2)
{
if (g.print_bytes)
{
- bytes = g.print_bytes;
+ bytes = (UInt32)g.print_bytes;
iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
/*
{
fputs("DEBUG: Got USB pipe stalled during write\n", stderr);
- bytes = g.print_bytes;
+ bytes = (UInt32)g.print_bytes;
iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
}
sleep(5);
#endif /* DEBUG_WRITES */
- bytes = g.print_bytes;
+ bytes = (UInt32)g.print_bytes;
iostatus = (*g.classdriver)->WritePipe(g.classdriver, (UInt8*)print_ptr, &bytes, 0);
}
}
fprintf(stderr, "DEBUG: Sent %lld bytes...\n", (off_t)total_bytes);
- fputs("STATE: +cups-waiting-for-completed\n", stderr);
+ fputs("STATE: +cups-waiting-for-job-completed\n", stderr);
/*
* Signal the side channel thread to exit...
} while (g.wait_eof || !g.read_thread_stop); /* Abort from main thread tests error here */
+ /* Workaround for usb race condition. <rdar://problem/21882551> */
+ if (!g.wait_eof && g.use_generic_class_driver)
+ {
+ const char *pdl = getenv("FINAL_CONTENT_TYPE");
+ if (pdl && strcmp(pdl, "application/vnd.cups-postscript") == 0)
+ {
+ while (readstatus == kIOReturnSuccess && ((rbytes > 0 && readbuffer[rbytes-1] != 0x4) || rbytes == 0))
+ {
+ start = mach_absolute_time();
+
+ rbytes = sizeof(readbuffer);
+ readstatus = (*g.classdriver)->ReadPipe(g.classdriver, readbuffer, &rbytes);
+ if (readstatus == kIOReturnSuccess && rbytes > 0 && readbuffer[rbytes-1] == 0x4)
+ break;
+
+ /* Make sure this loop executes no more than once every 250 miliseconds... */
+ mach_wait_until(start + delay);
+ }
+ }
+ }
+
/*
* Let the main thread know that we have completed the read thread...
*/
fputs("DEBUG: CUPS_SC_CMD_GET_BIDI received from driver...\n",
stderr);
- data[0] = g.bidi_flag;
+ data[0] = (char)g.bidi_flag;
cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, 1, 1.0);
fprintf(stderr,
get_device_id(&status, data, &datalen);
cupsSideChannelWrite(command, CUPS_SC_STATUS_OK, data, datalen, 1.0);
- if (datalen < sizeof(data))
+ if ((size_t)datalen < sizeof(data))
data[datalen] = '\0';
else
data[sizeof(data) - 1] = '\0';
/*
* 'iterate_printers()' - Iterate over all the printers.
*/
-
-static void iterate_printers(iterator_callback_t callBack,
- void *userdata)
+static void iterate_printers(iterator_callback_t callBack, void *userdata)
{
Iterating = 1;
- mach_port_t masterPort = 0x0;
- kern_return_t kr = IOMasterPort (bootstrap_port, &masterPort);
-
- if (kr == kIOReturnSuccess && masterPort != 0x0)
- {
- io_iterator_t addIterator = 0x0;
+ iterator_reference_t reference = { callBack, userdata, true };
- iterator_reference_t reference = { callBack, userdata, true };
- IONotificationPortRef addNotification = IONotificationPortCreate(masterPort);
+ IONotificationPortRef addNotification = IONotificationPortCreate(kIOMasterPortDefault);
- int klass = kUSBPrintingClass;
- int subklass = kUSBPrintingSubclass;
+ int printingClass = kUSBPrintingClass;
+ int printingSubclass = kUSBPrintingSubclass;
- CFNumberRef usb_klass = CFNumberCreate(NULL, kCFNumberIntType, &klass);
- CFNumberRef usb_subklass = CFNumberCreate(NULL, kCFNumberIntType, &subklass);
- CFMutableDictionaryRef usbPrinterMatchDictionary = IOServiceMatching(kIOUSBInterfaceClassName);
+ CFNumberRef interfaceClass = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &printingClass);
+ CFNumberRef interfaceSubClass = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &printingSubclass);
- CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceClass"), usb_klass);
- CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceSubClass"), usb_subklass);
+ CFMutableDictionaryRef usbPrinterMatchDictionary = IOServiceMatching(kIOUSBInterfaceClassName);
+ CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceClass"), interfaceClass);
+ CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceSubClass"), interfaceSubClass);
- CFRelease(usb_klass);
- CFRelease(usb_subklass);
+ CFRelease(interfaceClass);
+ CFRelease(interfaceSubClass);
- IOServiceAddMatchingNotification(addNotification, kIOMatchedNotification, usbPrinterMatchDictionary, &device_added, &reference, &addIterator);
- if (addIterator != 0x0)
+ io_iterator_t add_iterator = IO_OBJECT_NULL;
+ IOServiceAddMatchingNotification(addNotification, kIOMatchedNotification,
+ usbPrinterMatchDictionary, &device_added, &reference, &add_iterator);
+ if (add_iterator != IO_OBJECT_NULL)
+ {
+ device_added (&reference, add_iterator);
+ if (reference.keepRunning)
{
- device_added (&reference, addIterator);
-
- if (reference.keepRunning)
- {
- CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(addNotification), kCFRunLoopDefaultMode);
- CFRunLoopRun();
- }
- IOObjectRelease(addIterator);
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(addNotification), kCFRunLoopDefaultMode);
+ CFRunLoopRun();
}
- mach_port_deallocate(mach_task_self(), masterPort);
+ IOObjectRelease(add_iterator);
}
-
Iterating = 0;
}
/*
* 'device_added()' - Device added notifier.
*/
-
-static void device_added(void *userdata,
- io_iterator_t iterator)
+static void device_added(void *userdata, io_iterator_t iterator)
{
iterator_reference_t *reference = userdata;
+ io_service_t intf;
- io_service_t obj;
- while (reference->keepRunning && (obj = IOIteratorNext(iterator)) != 0x0)
+ while (reference->keepRunning && (intf = IOIteratorNext(iterator)) != 0x0)
{
- if (reference->callback != NULL)
- reference->keepRunning = reference->callback(reference->userdata, obj);
+ printer_interface_t printerIntf = usb_printer_interface_interface(intf);
+ if (printerIntf != NULL)
+ {
+ UInt8 intfClass = 0, intfSubClass = 0;
- IOObjectRelease(obj);
- }
+ (*printerIntf)->GetInterfaceClass(printerIntf, &intfClass);
+ (*printerIntf)->GetInterfaceSubClass(printerIntf, &intfSubClass);
+ if (intfClass == kUSBPrintingInterfaceClass && intfSubClass == kUSBPrintingSubclass)
+ reference->keepRunning = reference->callback(intf, printerIntf, userdata);
+ (*printerIntf)->Release(printerIntf);
+ }
+ IOObjectRelease(intf);
+ }
- /* One last call to the call back now that we are not longer have printers left to iterate...
- */
- if (reference->keepRunning && reference->callback)
- reference->keepRunning = reference->callback(reference->userdata, 0x0);
+ if (reference->keepRunning && reference->callback)
+ reference->keepRunning = reference->callback(IO_OBJECT_NULL, NULL, reference->userdata);
- if (!reference->keepRunning)
- CFRunLoopStop(CFRunLoopGetCurrent());
+ if (!reference->keepRunning)
+ CFRunLoopStop(CFRunLoopGetCurrent());
}
-
/*
* 'list_device_cb()' - list_device iterator callback.
*/
-
-static Boolean list_device_cb(void *refcon,
- io_service_t obj)
+static Boolean list_device_cb(io_service_t obj, printer_interface_t printerIntf, void *refcon)
{
- Boolean keepRunning = (obj != 0x0);
-
-
(void)refcon;
- if (keepRunning)
+ if (obj != IO_OBJECT_NULL)
{
CFStringRef deviceIDString = NULL;
- UInt32 deviceLocation = 0;
- UInt8 interfaceNum = 0;
+ CFStringRef make = NULL;
+ CFStringRef model = NULL;
+ CFStringRef serial = NULL;
+ UInt32 intfLocation;
- copy_devicestring(obj, &deviceIDString, &deviceLocation, &interfaceNum);
- if (deviceIDString != NULL)
- {
- CFStringRef make = NULL, model = NULL, serial = NULL;
- char uristr[1024], makestr[1024], modelstr[1024], serialstr[1024];
- char optionsstr[1024], idstr[1024], make_modelstr[1024];
+ deviceIDString = copy_printer_interface_deviceid(printerIntf, 0);
+ if (deviceIDString == NULL)
+ goto list_device_done;
- copy_deviceinfo(deviceIDString, &make, &model, &serial);
- CFStringGetCString(deviceIDString, idstr, sizeof(idstr),
- kCFStringEncodingUTF8);
- backendGetMakeModel(idstr, make_modelstr, sizeof(make_modelstr));
+ make = deviceIDCopyManufacturer(deviceIDString);
+ model = deviceIDCopyModel(deviceIDString);
+ serial = deviceIDCopySerialNumber(deviceIDString);
- modelstr[0] = '/';
+ char uristr[1024], makestr[1024], modelstr[1024], serialstr[1024];
+ char optionsstr[1024], idstr[1024], make_modelstr[1024];
- if (!make ||
- !CFStringGetCString(make, makestr, sizeof(makestr),
- kCFStringEncodingUTF8))
- strlcpy(makestr, "Unknown", sizeof(makestr));
+ CFStringGetCString(deviceIDString, idstr, sizeof(idstr), kCFStringEncodingUTF8);
+ backendGetMakeModel(idstr, make_modelstr, sizeof(make_modelstr));
- if (!model ||
- !CFStringGetCString(model, &modelstr[1], sizeof(modelstr)-1,
- kCFStringEncodingUTF8))
- strlcpy(modelstr + 1, "Printer", sizeof(modelstr) - 1);
+ modelstr[0] = '/';
- optionsstr[0] = '\0';
- if (serial != NULL)
- {
- CFStringGetCString(serial, serialstr, sizeof(serialstr), kCFStringEncodingUTF8);
- snprintf(optionsstr, sizeof(optionsstr), "?serial=%s", serialstr);
- }
- else if (deviceLocation != 0)
- snprintf(optionsstr, sizeof(optionsstr), "?location=%x", (unsigned)deviceLocation);
+ if (make == NULL || !CFStringGetCString(make, makestr, sizeof(makestr), kCFStringEncodingUTF8))
+ strlcpy(makestr, "Unknown", sizeof(makestr));
- httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
- strlcat(uristr, optionsstr, sizeof(uristr));
+ if (model == NULL || !CFStringGetCString(model, &modelstr[1], sizeof(modelstr)-1, kCFStringEncodingUTF8))
+ strlcpy(modelstr + 1, "Printer", sizeof(modelstr) - 1);
- cupsBackendReport("direct", uristr, make_modelstr, make_modelstr, idstr,
- NULL);
+ optionsstr[0] = '\0';
+ if (serial != NULL && CFStringGetCString(serial, serialstr, sizeof(serialstr), kCFStringEncodingUTF8))
+ snprintf(optionsstr, sizeof(optionsstr), "?serial=%s", serialstr);
+ else if ((*printerIntf)->GetLocationID(printerIntf, &intfLocation) == kIOReturnSuccess)
+ snprintf(optionsstr, sizeof(optionsstr), "?location=%x", (unsigned)intfLocation);
- release_deviceinfo(&make, &model, &serial);
- CFRelease(deviceIDString);
- }
- }
+ httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
+ strlcat(uristr, optionsstr, sizeof(uristr));
- return keepRunning;
-}
+ cupsBackendReport("direct", uristr, make_modelstr, make_modelstr, idstr,
+ NULL);
+ list_device_done:
+ if (make != NULL) CFRelease(make);
+ if (model != NULL) CFRelease(model);
+ if (serial != NULL) CFRelease(serial);
+ }
+ return obj != IO_OBJECT_NULL;
+}
/*
* 'find_device_cb()' - print_device iterator callback.
*/
-
-static Boolean find_device_cb(void *refcon,
- io_service_t obj)
+static Boolean find_device_cb(io_service_t obj, printer_interface_t printerIntf, void *refcon)
{
+ (void)refcon;
+
Boolean keepLooking = true;
- if (obj != 0x0)
+ if (obj != IO_OBJECT_NULL)
{
- CFStringRef idString = NULL;
- UInt32 location = -1;
- UInt8 interfaceNum = 0;
+ CFStringRef deviceIDString = NULL;
+ CFStringRef make = NULL;
+ CFStringRef model = NULL;
+ CFStringRef serial = NULL;
- copy_devicestring(obj, &idString, &location, &interfaceNum);
- if (idString != NULL)
- {
- CFStringRef make = NULL, model = NULL, serial = NULL;
+ deviceIDString = copy_printer_interface_deviceid(printerIntf, 0);
+ if (deviceIDString == NULL)
+ goto find_device_done;
- copy_deviceinfo(idString, &make, &model, &serial);
- if (make && CFStringCompare(make, g.make, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
- {
- if (model && CFStringCompare(model, g.model, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
- {
- if (g.serial != NULL && CFStringGetLength(g.serial) > 0)
- {
- if (serial != NULL && CFStringCompare(serial, g.serial, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
- {
- IOObjectRetain(obj);
- g.printer_obj = obj;
- keepLooking = false;
- }
- }
- else
- {
- if (g.printer_obj != 0)
- IOObjectRelease(g.printer_obj);
+ make = deviceIDCopyManufacturer(deviceIDString);
+ model = deviceIDCopyModel(deviceIDString);
+ serial = deviceIDCopySerialNumber(deviceIDString);
- g.printer_obj = obj;
- IOObjectRetain(obj);
+ if (make && CFStringCompare(make, g.make, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ {
+ if (model && CFStringCompare(model, g.model, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ {
+ UInt8 intfAltSetting = 0, intfNumber = 0, intfProtocol = 0;
+ UInt32 intfLocation = 0;
+
+ (*printerIntf)->GetInterfaceProtocol(printerIntf, &intfProtocol);
+ (*printerIntf)->GetAlternateSetting(printerIntf, &intfAltSetting);
+ (*printerIntf)->GetInterfaceNumber(printerIntf, &intfNumber);
+ (*printerIntf)->GetLocationID(printerIntf, &intfLocation);
+
+ if (intfProtocol == kUSBPrintingProtocolIPP)
+ return keepLooking;
+
+ if (g.serial != NULL && CFStringGetLength(g.serial) > 0)
+ {
+ if (serial != NULL && CFStringCompare(serial, g.serial, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+ {
+ g.interfaceProtocol = intfProtocol;
+ g.location = intfLocation;
+ g.alternateSetting = intfAltSetting;
+ g.printer_obj = obj;
+ IOObjectRetain(obj);
+ keepLooking = false;
+ }
+ }
+ else
+ {
+ if (g.printer_obj != 0)
+ IOObjectRelease(g.printer_obj);
+
+ if (g.location == 0 || g.location == intfLocation)
+ keepLooking = false;
+
+ g.location = intfLocation;
+ g.alternateSetting = intfAltSetting;
+ g.interfaceProtocol = intfProtocol;
+ g.printer_obj = obj;
+ IOObjectRetain(obj);
+ }
- if (g.location == 0 || g.location == location)
- keepLooking = false;
- }
- if ( !keepLooking )
- g.interfaceNum = interfaceNum;
- }
+ if (!keepLooking)
+ g.interfaceNum = intfNumber;
}
-
- release_deviceinfo(&make, &model, &serial);
- CFRelease(idString);
}
+
+ find_device_done:
+ if (deviceIDString != NULL) CFRelease(deviceIDString);
+ if (make != NULL) CFRelease(make);
+ if (model != NULL) CFRelease(model);
+ if (serial != NULL) CFRelease(serial);
}
else
{
- keepLooking = (g.printer_obj == 0);
- if (obj == 0x0 && keepLooking)
+ keepLooking = (g.printer_obj == 0 && g.interfaceProtocol != kUSBPrintingProtocolIPP);
+ if (obj == IO_OBJECT_NULL && keepLooking)
{
CFRunLoopTimerContext context = { 0, refcon, NULL, NULL, NULL };
CFRunLoopTimerRef timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + 1.0, 10, 0x0, 0x0, status_timer_cb, &context);
if (timer != NULL)
{
- CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
- g.status_timer = timer;
+ CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
+ g.status_timer = timer;
}
}
}
return keepLooking;
}
+static CFStringRef deviceIDCopySerialNumber(CFStringRef deviceID)
+{
+ CFStringRef serialKeys[] = { CFSTR("SN:"), CFSTR("SERN:"), NULL };
+
+ return copy_value_for_key(deviceID, serialKeys);
+}
+
+static CFStringRef deviceIDCopyModel(CFStringRef deviceID)
+{
+ CFStringRef modelKeys[] = { CFSTR("MDL:"), CFSTR("MODEL:"), NULL };
+ return copy_value_for_key(deviceID, modelKeys);
+}
+
+static CFStringRef deviceIDCopyManufacturer(CFStringRef deviceID)
+{
+ CFStringRef makeKeys[] = { CFSTR("MFG:"), CFSTR("MANUFACTURER:"), NULL };
+ return copy_value_for_key(deviceID, makeKeys);
+}
/*
* 'status_timer_cb()' - Status timer callback.
}
-#pragma mark -
-/*
- * 'copy_deviceinfo()' - Copy strings from the 1284 device ID.
- */
-
-static void copy_deviceinfo(CFStringRef deviceIDString,
- CFStringRef *make,
- CFStringRef *model,
- CFStringRef *serial)
-{
- CFStringRef modelKeys[] = { CFSTR("MDL:"), CFSTR("MODEL:"), NULL };
- CFStringRef makeKeys[] = { CFSTR("MFG:"), CFSTR("MANUFACTURER:"), NULL };
- CFStringRef serialKeys[] = { CFSTR("SN:"), CFSTR("SERN:"), NULL };
-
- if (make != NULL)
- *make = copy_value_for_key(deviceIDString, makeKeys);
-
- if (model != NULL)
- *model = copy_value_for_key(deviceIDString, modelKeys);
-
- if (serial != NULL)
- *serial = copy_value_for_key(deviceIDString, serialKeys);
-}
-
-
-/*
- * 'release_deviceinfo()' - Release deviceinfo strings.
- */
-
-static void release_deviceinfo(CFStringRef *make,
- CFStringRef *model,
- CFStringRef *serial)
-{
- if (make != NULL && *make != NULL)
- {
- CFRelease(*make);
- *make = NULL;
- }
-
- if (model != NULL && *model != NULL)
- {
- CFRelease(*model);
- *model = NULL;
- }
-
- if (serial != NULL && *serial != NULL)
- {
- CFRelease(*serial);
- *serial = NULL;
- }
-}
-
-
#pragma mark -
/*
* 'load_classdriver()' - Load a classdriver.
{
*driverBundlePath = IORegistryEntryCreateCFProperty(g.printer_obj, kUSBClassDriverProperty, NULL, kNilOptions);
+ g.use_generic_class_driver = (*driverBundlePath == NULL || (CFStringCompare(*driverBundlePath, kUSBGenericTOPrinterClassDriver, 0x0) == kCFCompareEqualTo));
kr = load_classdriver(*driverBundlePath, interface, &g.classdriver);
if (kr != kIOReturnSuccess)
return kr;
}
+static printer_interface_t usb_printer_interface_interface(io_service_t usbClass)
+{
+ printer_interface_t intf = NULL;
+ IOCFPlugInInterface **plugin = NULL;
+ SInt32 score;
+ int kr = IOCreatePlugInInterfaceForService(usbClass, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score);
+ if (kr == kIOReturnSuccess)
+ {
+ (*plugin)->QueryInterface(plugin, USB_INTERFACE_KIND, (LPVOID *)&intf);
+ IODestroyPlugInInterface(plugin);
+ }
+
+ return intf;
+}
+
+static CFStringRef copy_printer_interface_deviceid(printer_interface_t printer, UInt8 alternateSetting)
+{
+ // I have tried to make this function as neat as I can, but the possibility of needing to resend
+ // a request to get the entire string makes it hideous...
+ //
+ // We package the job of sending a request up into the block (^sendRequest), which takes the size
+ // it should allocate for the message buffer. It frees the current buffer if one is set and
+ // allocates one of the specified size, then performs the request. We can then easily retry by
+ // calling the block again if we fail to get the whole string the first time around.
+
+ #define kUSBPrintClassGetDeviceID 0
+ #define kDefaultNoDataTimeout 5000L
+ #define pack_device_id_wIndex(intf, alt) ((UInt16)((((UInt16)(intf)) << 8) | ((UInt8)(alt))))
+
+ if (printer == NULL)
+ return NULL;
+
+
+ IOReturn err = kIOReturnError;
+ UInt8 configurationIndex = 0;
+ UInt8 interfaceNumber = 0;
+ size_t bufferLength = 256;
+ CFStringRef ret = NULL;
+
+ if ((*printer)->GetConfigurationValue( printer, &configurationIndex) == kIOReturnSuccess &&
+ (*printer)->GetInterfaceNumber( printer, &interfaceNumber) == kIOReturnSuccess)
+ {
+ __block IOUSBDevRequestTO request;
+ IOReturn (^sendRequest)(size_t) = ^ (size_t size)
+ {
+ if (request.pData)
+ {
+ free(request.pData);
+ request.wLength = 0;
+ request.pData = NULL;
+ }
+
+ IOReturn berr = kIOReturnError;
+ char *buffer = malloc(size);
+ if (buffer == NULL)
+ return kIOReturnNoMemory;
+
+ request.wLength = HostToUSBWord(size);
+ request.pData = buffer;
+ berr = (*printer)->ControlRequestTO(printer, (UInt8)0, &request);
+ return berr;
+ };
+
+ /* This request takes the 0 based configuration index. IOKit returns a 1 based configuration index */
+ configurationIndex -= 1;
+
+ memset(&request, 0, sizeof(request));
+
+ request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBInterface);
+ request.bRequest = kUSBPrintClassGetDeviceID;
+ request.wValue = HostToUSBWord(configurationIndex);
+ request.wIndex = HostToUSBWord(pack_device_id_wIndex(interfaceNumber, alternateSetting));
+ request.noDataTimeout = kDefaultNoDataTimeout;
+ request.completionTimeout = 0; // Copying behavior from Generic Class Driver
+
+ err = sendRequest(bufferLength);
+
+ if (err == kIOReturnSuccess && request.wLenDone > 1)
+ {
+ UInt16 actualLength = OSSwapBigToHostInt16(*((UInt16 *)request.pData));
+
+ if (actualLength > 2 && actualLength <= bufferLength - 2)
+ {
+ ret = CFStringCreateWithBytes(NULL, (const UInt8 *) &request.pData[2], actualLength - 2, kCFStringEncodingUTF8, false);
+ }
+ else if (actualLength > 2) {
+ err = sendRequest(actualLength);
+ if (err == kIOReturnSuccess && request.wLenDone > 0)
+ {
+ actualLength = OSSwapBigToHostInt16(*((UInt16 *)request.pData));
+ ret = CFStringCreateWithBytes(NULL, (const UInt8 *) &request.pData[2], actualLength - 2, kCFStringEncodingUTF8, false);
+ }
+ }
+ }
+
+ if (request.pData)
+ free(request.pData);
+ }
+
+ CFStringRef manufacturer = deviceIDCopyManufacturer(ret);
+ CFStringRef model = deviceIDCopyModel(ret);
+ CFStringRef serial = deviceIDCopySerialNumber(ret);
+
+ if (manufacturer == NULL || serial == NULL || model == NULL)
+ {
+ IOUSBDevRequestTO request;
+ IOUSBDeviceDescriptor desc;
+
+ memset(&request, 0, sizeof(request));
+
+ request.bmRequestType = USBmakebmRequestType( kUSBIn, kUSBStandard, kUSBDevice );
+ request.bRequest = kUSBRqGetDescriptor;
+ request.wValue = kUSBDeviceDesc << 8;
+ request.wIndex = 0;
+ request.wLength = sizeof(desc);
+ request.pData = &desc;
+ request.completionTimeout = 0;
+ request.noDataTimeout = 60L;
+
+ err = (*printer)->ControlRequestTO(printer, 0, &request);
+ if (err == kIOReturnSuccess)
+ {
+ CFMutableStringRef extras = CFStringCreateMutable(NULL, 0);
+ if (manufacturer == NULL)
+ {
+ manufacturer = copy_printer_interface_indexed_description(printer, desc.iManufacturer, kUSBLanguageEnglish);
+ if (manufacturer && CFStringGetLength(manufacturer) > 0)
+ CFStringAppendFormat(extras, NULL, CFSTR("MFG:%@;"), manufacturer);
+ }
+
+ if (model == NULL)
+ {
+ model = copy_printer_interface_indexed_description(printer, desc.iProduct, kUSBLanguageEnglish);
+ if (model && CFStringGetLength(model) > 0)
+ CFStringAppendFormat(extras, NULL, CFSTR("MDL:%@;"), model);
+ }
+
+ if (desc.iSerialNumber != 0)
+ {
+ // Always look at the USB serial number since some printers
+ // incorrectly include a bogus static serial number in their
+ // IEEE-1284 device ID string...
+ CFStringRef userial = copy_printer_interface_indexed_description(printer, desc.iSerialNumber, kUSBLanguageEnglish);
+ if (userial && CFStringGetLength(userial) > 0 && (serial == NULL || CFStringCompare(serial, userial, kCFCompareCaseInsensitive) != kCFCompareEqualTo))
+ {
+ if (serial != NULL)
+ {
+ // 1284 serial number doesn't match USB serial number, so replace the existing SERN: in device ID
+ CFRange range = CFStringFind(ret, serial, 0);
+ CFMutableStringRef deviceIDString = CFStringCreateMutableCopy(NULL, 0, ret);
+ CFStringReplace(deviceIDString, range, userial);
+ CFRelease(ret);
+ ret = deviceIDString;
+
+ CFRelease(serial);
+ }
+ else
+ {
+ // No 1284 serial number so add SERN: with USB serial number to device ID
+ CFStringAppendFormat(extras, NULL, CFSTR("SERN:%@;"), userial);
+ }
+ serial = userial;
+ }
+ else if (userial != NULL)
+ CFRelease(userial);
+ }
+
+ if (ret != NULL)
+ {
+ CFStringAppend(extras, ret);
+ CFRelease(ret);
+
+ ret = extras;
+ }
+ else
+ {
+ ret = extras;
+ }
+ }
+ }
+
+ if (ret != NULL)
+ {
+ /* Remove special characters from the serial number */
+ CFRange range = (serial != NULL ? CFStringFind(serial, CFSTR("+"), 0) : CFRangeMake(0, 0));
+ if (range.length == 1)
+ {
+ range = CFStringFind(ret, serial, 0);
+
+ CFMutableStringRef deviceIDString = CFStringCreateMutableCopy(NULL, 0, ret);
+ CFRelease(ret);
+
+ ret = deviceIDString;
+ CFStringFindAndReplace(deviceIDString, CFSTR("+"), CFSTR(""), range, 0);
+ }
+ }
+
+ if (manufacturer != NULL)
+ CFRelease(manufacturer);
+
+ if (model != NULL)
+ CFRelease(model);
+
+ if (serial != NULL)
+ CFRelease(serial);
+
+ if (ret != NULL && CFStringGetLength(ret) == 0)
+ {
+ CFRelease(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+static CFStringRef copy_printer_interface_indexed_description(printer_interface_t printer, UInt8 index, UInt16 language)
+{
+ IOReturn err;
+ UInt8 description[256]; // Max possible descriptor length
+ IOUSBDevRequestTO request;
+
+ memset(description, 0, 2);
+
+ request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+ request.bRequest = kUSBRqGetDescriptor;
+ request.wValue = (kUSBStringDesc << 8) | index;
+ request.wIndex = language;
+ request.wLength = 2;
+ request.pData = &description;
+ request.completionTimeout = 0;
+ request.noDataTimeout = 60L;
+
+ err = (*printer)->ControlRequestTO(printer, 0, &request);
+ if (err != kIOReturnSuccess && err != kIOReturnOverrun)
+ {
+ memset(description, 0, request.wLength);
+
+ // Let's try again full length. Here's why:
+ // On USB 2.0 controllers, we will not get an overrun error. We just get a "babble" error
+ // and no valid data. So, if we ask for the max size, we will either get it, or we'll get an underrun.
+ // It looks like we get it w/out an underrun
+
+ request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+ request.bRequest = kUSBRqGetDescriptor;
+ request.wValue = (kUSBStringDesc << 8) | index;
+ request.wIndex = language;
+ request.wLength = sizeof description;
+ request.pData = &description;
+ request.completionTimeout = 0;
+ request.noDataTimeout = 60L;
+
+ err = (*printer)->ControlRequestTO(printer, 0, &request);
+ if (err != kIOReturnSuccess && err != kIOReturnUnderrun)
+ return NULL;
+ }
+
+ unsigned int length = description[0];
+ if (length == 0)
+ return CFStringCreateWithCString(NULL, "", kCFStringEncodingUTF8);
+
+ if (description[1] != kUSBStringDesc)
+ return NULL;
+
+ request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+ request.bRequest = kUSBRqGetDescriptor;
+ request.wValue = (kUSBStringDesc << 8) | index;
+ request.wIndex = language;
+
+ memset(description, 0, length);
+ request.wLength = (UInt16)length;
+ request.pData = &description;
+ request.completionTimeout = 0;
+ request.noDataTimeout = 60L;
+
+ err = (*printer)->ControlRequestTO(printer, 0, &request);
+ if (err != kIOReturnSuccess)
+ return NULL;
+
+ if (description[1] != kUSBStringDesc)
+ return NULL;
+
+ if ((description[0] & 1) != 0)
+ description[0] &= 0xfe;
+
+ char buffer[258] = {};
+ unsigned int maxLength = sizeof buffer;
+ if (description[0] > 1)
+ {
+ length = (description[0]-2)/2;
+
+ if (length > maxLength - 1)
+ length = maxLength -1;
+
+ for (unsigned i = 0; i < length; i++)
+ buffer[i] = (char) description[2*i+2];
+
+ buffer[length] = 0;
+ }
+
+ return CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+}
/*
* 'registry_open()' - Open a connection to the printer.
return kIOReturnSuccess;
}
-
-/*
- * 'copy_deviceid()' - Copy the 1284 device id string.
- */
-
-static OSStatus copy_deviceid(classdriver_t **classdriver,
- CFStringRef *deviceID)
-{
- CFStringRef devID = NULL;
- CFStringRef deviceMake = NULL;
- CFStringRef deviceModel = NULL;
- CFStringRef deviceSerial = NULL;
-
- *deviceID = NULL;
-
- OSStatus err = (*classdriver)->GetDeviceID(classdriver, &devID, DEFAULT_TIMEOUT);
-
- copy_deviceinfo(devID, &deviceMake, &deviceModel, &deviceSerial);
-
- if (deviceMake == NULL || deviceModel == NULL || deviceSerial == NULL)
- {
- IOUSBDeviceDescriptor desc;
- iodevice_request_t request;
-
- request.requestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
- request.request = kUSBRqGetDescriptor;
- request.value = (kUSBDeviceDesc << 8) | 0;
- request.index = 0;
- request.length = sizeof(desc);
- request.buffer = &desc;
- err = (*classdriver)->DeviceRequest(classdriver, &request, DEFAULT_TIMEOUT);
- if (err == kIOReturnSuccess)
- {
- CFMutableStringRef newDevID = CFStringCreateMutable(NULL, 0);
-
- if (deviceMake == NULL)
- {
- CFStringRef data = NULL;
- err = (*classdriver)->GetString(classdriver, desc.iManufacturer, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &data);
- if (data != NULL)
- {
- CFStringAppendFormat(newDevID, NULL, CFSTR("MFG:%@;"), data);
- CFRelease(data);
- }
- }
-
- if (deviceModel == NULL)
- {
- CFStringRef data = NULL;
- err = (*classdriver)->GetString(classdriver, desc.iProduct, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &data);
- if (data != NULL)
- {
- CFStringAppendFormat(newDevID, NULL, CFSTR("MDL:%@;"), data);
- CFRelease(data);
- }
- }
-
- if (deviceSerial == NULL && desc.iSerialNumber != 0)
- {
- err = (*classdriver)->GetString(classdriver, desc.iSerialNumber, kUSBLanguageEnglish, DEFAULT_TIMEOUT, &deviceSerial);
- if (deviceSerial != NULL)
- {
- CFStringAppendFormat(newDevID, NULL, CFSTR("SERN:%@;"), deviceSerial);
- }
- }
-
- if (devID != NULL)
- {
- CFStringAppend(newDevID, devID);
- CFRelease(devID);
- }
-
- *deviceID = newDevID;
- }
- }
- else
- {
- *deviceID = devID;
- }
-
- if (*deviceID == NULL)
- return err;
-
- /* Remove special characters from the serial number */
- CFRange range = (deviceSerial != NULL ? CFStringFind(deviceSerial, CFSTR("+"), 0) : CFRangeMake(0, 0));
- if (range.length == 1) {
- range = CFStringFind(*deviceID, deviceSerial, 0);
-
- CFMutableStringRef deviceIDString = CFStringCreateMutableCopy(NULL, 0, *deviceID);
- CFStringFindAndReplace(deviceIDString, CFSTR("+"), CFSTR(""), range, 0);
- CFRelease(*deviceID);
- *deviceID = deviceIDString;
- }
-
- release_deviceinfo(&deviceMake, &deviceModel, &deviceSerial);
-
- return err;
-}
-
-
-/*
- * 'copy_devicestring()' - Copy the 1284 device id string.
- */
-
-static void copy_devicestring(io_service_t usbInterface,
- CFStringRef *deviceID,
- UInt32 *deviceLocation,
- UInt8 *interfaceNumber )
-{
- IOCFPlugInInterface **iodev = NULL;
- SInt32 score;
- kern_return_t kr;
- printer_interface_t interface;
- HRESULT res;
- classdriver_t **klassDriver = NULL;
- CFStringRef driverBundlePath;
-
- if ((kr = IOCreatePlugInInterfaceForService(usbInterface,
- kIOUSBInterfaceUserClientTypeID,
- kIOCFPlugInInterfaceID,
- &iodev, &score)) == kIOReturnSuccess)
- {
- if ((res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *)
- &interface)) == noErr)
- {
- (*interface)->GetLocationID(interface, deviceLocation);
- (*interface)->GetInterfaceNumber(interface, interfaceNumber);
-
- driverBundlePath = IORegistryEntryCreateCFProperty(usbInterface,
- kUSBClassDriverProperty,
- NULL, kNilOptions);
-
- kr = load_classdriver(driverBundlePath, interface, &klassDriver);
-
- if (kr != kIOReturnSuccess && driverBundlePath != NULL)
- kr = load_classdriver(NULL, interface, &klassDriver);
-
- if (kr == kIOReturnSuccess && klassDriver != NULL)
- copy_deviceid(klassDriver, deviceID);
-
- unload_classdriver(&klassDriver);
-
- if (driverBundlePath != NULL)
- CFRelease(driverBundlePath);
-
- /* (*interface)->Release(interface); */
- }
- IODestroyPlugInInterface(iodev);
- }
-}
-
-
#pragma mark -
/*
* 'copy_value_for_key()' - Copy value string associated with a key.
value);
}
else if (!_cups_strcasecmp(name, "serial"))
- strlcpy(serial, value, serial_size);
+ strlcpy(serial, value, (size_t)serial_size);
else if (!_cups_strcasecmp(name, "location") && location)
- *location = strtol(value, NULL, 16);
+ *location = (UInt32)strtoul(value, NULL, 16);
}
}
}
#pragma mark -
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__arm64e__)
/*!
* @function run_legacy_backend
*
- * @abstract Starts child backend process running as a ppc or i386 executable.
+ * @abstract Starts child backend process running as a x86_64 executable.
*
* @result Never returns; always calls exit().
*
char *my_argv[32];
char *usb_legacy_status;
+
/*
- * If we're running as x86_64 or i386 and couldn't load the class driver
- * (because it's ppc or i386), then try to re-exec ourselves in ppc or i386
- * mode to try again. If we don't have a ppc or i386 architecture we may be
+ * If we're running as ARM and couldn't load the class driver
+ * (because it's x86_64, i386 or ppc), then try to re-exec ourselves in x86_64
+ * mode to try again. If we don't have that architecture we may be
* running with the same architecture again so guard against this by setting
* and testing an environment variable...
*/
-# ifdef __x86_64__
- usb_legacy_status = getenv("USB_I386_STATUS");
-# else
- usb_legacy_status = getenv("USB_PPC_STATUS");
-# endif /* __x86_64__ */
+ usb_legacy_status = getenv("USB_LEGACY_STATUS");
if (!usb_legacy_status)
{
* Set the environment variable...
*/
-# ifdef __x86_64__
- setenv("USB_I386_STATUS", "1", false);
-# else
- setenv("USB_PPC_STATUS", "1", false);
-# endif /* __x86_64__ */
+ setenv("USB_LEGACY_STATUS", "1", false);
/*
* Tell the kernel to use the specified CPU architecture...
*/
-# ifdef __x86_64__
- cpu_type_t cpu = CPU_TYPE_I386;
-# else
- cpu_type_t cpu = CPU_TYPE_POWERPC;
-# endif /* __x86_64__ */
+ cpu_type_t cpu = CPU_TYPE_X86_64;
size_t ocount = 1;
posix_spawnattr_t attrs;
posix_spawnattr_setsigdefault(&attrs, &oldmask);
if (posix_spawnattr_setbinpref_np(&attrs, 1, &cpu, &ocount) || ocount != 1)
{
-# ifdef __x86_64__
- perror("DEBUG: Unable to set binary preference to i386");
-# else
- perror("DEBUG: Unable to set binary preference to ppc");
-# endif /* __x86_64__ */
+ perror("DEBUG: Unable to set binary preference to X86_64");
_cupsLangPrintFilter(stderr, "ERROR",
_("Unable to use legacy USB class driver."));
exit(CUPS_BACKEND_STOP);
cups_serverbin = CUPS_SERVERBIN;
snprintf(usbpath, sizeof(usbpath), "%s/backend/usb", cups_serverbin);
- for (i = 0; i < argc && i < (sizeof(my_argv) / sizeof(my_argv[0])) - 1; i ++)
+ for (i = 0; i < argc && i < (int)(sizeof(my_argv) / sizeof(my_argv[0])) - 1; i ++)
my_argv[i] = argv[i];
my_argv[i] = NULL;
exit(exitstatus);
}
-#endif /* __i386__ || __x86_64__ */
-
/*
* 'sigterm_handler()' - SIGTERM handler.
static void
sigterm_handler(int sig) /* I - Signal */
{
-#if defined(__i386__) || defined(__x86_64__)
/*
* If we started a child process pass the signal on to it...
*/
while (waitpid(child_pid, &status, 0) < 0 && errno == EINTR);
if (WIFEXITED(status))
- exit(WEXITSTATUS(status));
+ _exit(WEXITSTATUS(status));
else if (status == SIGTERM || status == SIGKILL)
- exit(0);
+ _exit(0);
else
{
- fprintf(stderr, "DEBUG: Child crashed on signal %d\n", status);
- exit(CUPS_BACKEND_STOP);
+ backendMessage("DEBUG: Child crashed.\n");
+ _exit(CUPS_BACKEND_STOP);
}
}
-#endif /* __i386__ || __x86_64__ */
}
+#endif /* __arm64e__ */
/*
{
CFStringRef deviceIDString = NULL;
- /* GetDeviceID */
- copy_deviceid(g.classdriver, &deviceIDString);
+ if (g.printer_obj != IO_OBJECT_NULL)
+ {
+ printer_interface_t printerIntf = usb_printer_interface_interface(g.printer_obj);
+ if (printerIntf)
+ {
+ deviceIDString = copy_printer_interface_deviceid(printerIntf, g.alternateSetting);
+ (*printerIntf)->Release(printerIntf);
+ }
+ }
+
if (deviceIDString)
{
- CFStringGetCString(deviceIDString, data, *datalen, kCFStringEncodingUTF8);
- *datalen = strlen(data);
+ if (CFStringGetCString(deviceIDString, data, *datalen, kCFStringEncodingUTF8))
+ *datalen = (int)strlen(data);
+ else
+ *datalen = 0;
+
CFRelease(deviceIDString);
}
+ else
+ {
+ *datalen = 0;
+ }
+
*status = CUPS_SC_STATUS_OK;
}
-
-
-/*
- * End of "$Id$".
- */