]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - backend/usb-darwin.c
Merge pull request #5913 from apple/bug-fix-rollup-1
[thirdparty/cups.git] / backend / usb-darwin.c
index 17d62902bf39198c350ada28956fa5c84fcb5715..ee75b9e0d0c978ef2e52fe8dc9d92eeafcb42176 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * "$Id$"
+ * USB backend for macOS.
  *
- * Copyright 2005-2015 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
@@ -204,7 +204,7 @@ typedef struct classdriver_s                /**** g.classdriver context ****/
 
 } classdriver_t;
 
-typedef Boolean (*iterator_callback_t)(void *refcon, io_service_t obj, CFStringRef deviceIDString, UInt32 deviceLocation, UInt8 interfaceNum, UInt8 alternateSetting);
+typedef Boolean (*iterator_callback_t)(io_service_t obj, printer_interface_t printerIntf, void *refcon);
 
 typedef struct iterator_reference_s    /**** Iterator reference data */
 {
@@ -233,6 +233,7 @@ typedef struct globals_s
   UInt32               location;
   UInt8                        interfaceNum;
   UInt8                        alternateSetting;
+  UInt8                 interfaceProtocol;
 
   CFRunLoopTimerRef    status_timer;
 
@@ -266,8 +267,8 @@ int Iterating = 0;                  /* Are we iterating the bus? */
  * Local functions...
  */
 
-static Boolean find_device_cb(void *refcon, io_service_t obj, CFStringRef deviceIDString, UInt32 deviceLocation, UInt8 interfaceNum, UInt8 alternateSetting);
-static Boolean list_device_cb(void *refcon, io_service_t obj, CFStringRef deviceIDString, UInt32 deviceLocation, UInt8 interfaceNum, UInt8 alternateSetting);
+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);
@@ -286,16 +287,15 @@ static void parse_options(char *options, char *serial, int serial_size, UInt32 *
 static void setup_cfLanguage(void);
 static void soft_reset(void);
 static void status_timer_cb(CFRunLoopTimerRef timer, void *info);
-static void log_usb_class_driver(int is_64bit);
 #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) __attribute__((noreturn));      /* 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) __attribute__((noreturn));
+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);
@@ -303,7 +303,7 @@ 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 IOUSBDeviceInterface **usb_device_interface_for_device(io_service_t usbDevice);
+
 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);
@@ -420,10 +420,17 @@ print_device(const char *uri,             /* I - Device URI */
       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);
 
@@ -431,18 +438,18 @@ print_device(const char *uri,             /* I - Device URI */
 
     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)
     {
@@ -465,11 +472,6 @@ print_device(const char *uri,              /* I - Device URI */
       return (CUPS_BACKEND_STOP);
     }
 
-#ifdef __x86_64__
-    if (status == noErr && driverBundlePath != NULL && CFStringCompare(driverBundlePath, kUSBGenericTOPrinterClassDriver, 0) != kCFCompareEqualTo)
-      log_usb_class_driver(IS_64BIT);
-#endif /* __x86_64__ */
-
     if (driverBundlePath)
       CFRelease(driverBundlePath);
 
@@ -1118,257 +1120,234 @@ sidechannel_thread(void *reference)
 /*
  * 'iterate_printers()' - Iterate over all the printers.
  */
-
 static void iterate_printers(iterator_callback_t callBack, void *userdata)
 {
-    Iterating = 1;
+  Iterating = 1;
 
-    mach_port_t        masterPort = 0x0;
-    kern_return_t kr = IOMasterPort (bootstrap_port, &masterPort);
+  iterator_reference_t reference = { callBack, userdata, true };
 
-    if (kr == kIOReturnSuccess && masterPort != 0x0)
-    {
-        iterator_reference_t reference = { callBack, userdata, true };
+  IONotificationPortRef addNotification = IONotificationPortCreate(kIOMasterPortDefault);
 
-        IONotificationPortRef addNotification = IONotificationPortCreate(masterPort);
-        io_iterator_t addIterator = IO_OBJECT_NULL;
+  int printingClass = kUSBPrintingClass;
+  int printingSubclass = kUSBPrintingSubclass;
 
-        kr = IOServiceAddMatchingNotification(addNotification, kIOFirstMatchNotification, IOServiceMatching(kIOUSBDeviceClassName),
-                                              &device_added, &reference, &addIterator);
-        if (kr == kIOReturnSuccess && addIterator != IO_OBJECT_NULL)
-        {
-            device_added(&reference, addIterator);
-            if (reference.keepRunning)
-            {
-                CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(addNotification), kCFRunLoopDefaultMode);
-                CFRunLoopRun();
-            }
-            IOObjectRelease(addIterator);
-        }
-        mach_port_deallocate(mach_task_self(), masterPort);
-    }
+  CFNumberRef interfaceClass = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &printingClass);
+  CFNumberRef interfaceSubClass = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &printingSubclass);
 
-    Iterating = 0;
+  CFMutableDictionaryRef usbPrinterMatchDictionary = IOServiceMatching(kIOUSBInterfaceClassName);
+  CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceClass"), interfaceClass);
+  CFDictionaryAddValue(usbPrinterMatchDictionary, CFSTR("bInterfaceSubClass"), interfaceSubClass);
+
+  CFRelease(interfaceClass);
+  CFRelease(interfaceSubClass);
+
+  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)
+    {
+      CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(addNotification), kCFRunLoopDefaultMode);
+      CFRunLoopRun();
+    }
+    IOObjectRelease(add_iterator);
+  }
+  Iterating = 0;
 }
 
 
 /*
  * 'device_added()' - Device added notifier.
  */
-#define IsPrintingInterface(c,s,p) ((c) == kUSBPrintingInterfaceClass && (s) == kUSBPrintingSubclass && (p) != kUSBPrintingProtocolIPP)
-
 static void device_added(void *userdata, io_iterator_t iterator)
 {
-    iterator_reference_t *reference = userdata;
-    io_service_t device;
+  iterator_reference_t *reference = userdata;
+  io_service_t intf;
 
-    while (reference->keepRunning && (device = IOIteratorNext(iterator)) != 0x0)
+  while (reference->keepRunning && (intf = IOIteratorNext(iterator)) != 0x0)
+  {
+    printer_interface_t printerIntf = usb_printer_interface_interface(intf);
+    if (printerIntf != NULL)
     {
-        UInt32 locationID = 0;
-        IOUSBDeviceInterface **devIntf = NULL;
-        io_iterator_t intfIterator = IO_OBJECT_NULL;
-        io_object_t intf = IO_OBJECT_NULL;
-
-        devIntf = usb_device_interface_for_device(device);
-        if (devIntf == NULL)
-            goto device_added_done;
-
-        UInt16 vendorUniqueID;
-        if ((*devIntf)->GetDeviceVendor(devIntf, &vendorUniqueID) != kIOReturnSuccess || vendorUniqueID == kAppleVendorID || vendorUniqueID == 0x0A5C)
-            goto device_added_done;
-
-        if ((*devIntf)->GetLocationID(devIntf, &locationID) != kIOReturnSuccess)
-            goto device_added_done;
-
-        IOUSBFindInterfaceRequest req = { kIOUSBFindInterfaceDontCare, kIOUSBFindInterfaceDontCare, kIOUSBFindInterfaceDontCare, kIOUSBFindInterfaceDontCare };
-        if ((*devIntf)->CreateInterfaceIterator(devIntf, &req, &intfIterator) != kIOReturnSuccess)
-            goto device_added_done;
-
-        while (reference->keepRunning && (intf = IOIteratorNext(intfIterator)))
-        {
-            printer_interface_t printerIntf = usb_printer_interface_interface(intf);
-            if (printerIntf != NULL)
-            {
-                UInt8 intfClass = 0, intfSubclass = 0, intfProtocol = 0, intfNumber = 0;
-
-                (*printerIntf)->GetInterfaceClass(printerIntf, &intfClass);
-                (*printerIntf)->GetInterfaceSubClass(printerIntf, &intfSubclass);
-                (*printerIntf)->GetInterfaceProtocol(printerIntf, &intfProtocol);
-                (*printerIntf)->GetInterfaceNumber(printerIntf, &intfNumber);
-
-                if (IsPrintingInterface(intfClass, intfSubclass, intfProtocol))
-                {
-                    CFStringRef deviceIDString = copy_printer_interface_deviceid(printerIntf, 0);
-                    if (deviceIDString != NULL)
-                    {
-                        reference->keepRunning = reference->callback(userdata, intf, deviceIDString, locationID, intfNumber, 0);
-                        CFRelease(deviceIDString);
-                    }
-                }
-
-                IOUSBInterfaceDescriptor *intfDesc = NULL;
-                while (reference->keepRunning && (intfDesc = (IOUSBInterfaceDescriptor *)(*printerIntf)->FindNextAssociatedDescriptor(printerIntf, intfDesc, kUSBInterfaceDesc)))
-                {
-                    intfClass = intfDesc->bInterfaceClass;
-                    intfSubclass = intfDesc->bInterfaceSubClass;
-                    intfProtocol = intfDesc->bInterfaceProtocol;
-
-                    if ((IsPrintingInterface(intfClass, intfSubclass, intfProtocol)))
-                    {
-                        CFStringRef deviceIDString = copy_printer_interface_deviceid(printerIntf, intfDesc->bAlternateSetting);
-                        if (deviceIDString != NULL)
-                        {
-                            reference->keepRunning = reference->callback(userdata, intf, deviceIDString, locationID, intfNumber, intfDesc->bAlternateSetting);
-                            CFRelease(deviceIDString);
-                        }
-                    }
-                }
-                (*printerIntf)->Release(printerIntf);
-            }
-            IOObjectRelease(intf);
-        }
+      UInt8 intfClass = 0, intfSubClass = 0;
 
-        device_added_done:
-            if (devIntf != NULL) (*devIntf)->Release(devIntf);
-            if (intfIterator != IO_OBJECT_NULL) IOObjectRelease(intfIterator);
-
-        IOObjectRelease(device);
+      (*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, IO_OBJECT_NULL, NULL, 0, 0, 0);
+      reference->keepRunning = reference->callback(IO_OBJECT_NULL, NULL, reference->userdata);
 
     if (!reference->keepRunning)
-        CFRunLoopStop(CFRunLoopGetCurrent());
+      CFRunLoopStop(CFRunLoopGetCurrent());
 }
 
 /*
  * 'list_device_cb()' - list_device iterator callback.
  */
-
-static Boolean list_device_cb(void *refcon, io_service_t obj, CFStringRef deviceIDString, UInt32 deviceLocation, UInt8 interfaceNum, UInt8 alternateSetting)
+static Boolean list_device_cb(io_service_t obj, printer_interface_t printerIntf, void *refcon)
 {
-    (void)refcon;
-    (void)interfaceNum;
-    (void)alternateSetting;
+  (void)refcon;
 
-    if (obj != IO_OBJECT_NULL)
-    {
-        CFStringRef make = deviceIDCopyManufacturer(deviceIDString);
-        CFStringRef model = deviceIDCopyModel(deviceIDString);
-        CFStringRef serial = deviceIDCopySerialNumber(deviceIDString);
+  if (obj != IO_OBJECT_NULL)
+  {
+    CFStringRef deviceIDString = NULL;
+    CFStringRef make = NULL;
+    CFStringRef model = NULL;
+    CFStringRef serial = NULL;
+    UInt32 intfLocation;
 
-        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;
 
-        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  == NULL || !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 == NULL || !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);
 
-        if (make != NULL) CFRelease(make);
-        if (model != NULL) CFRelease(model);
-        if (serial != NULL) CFRelease(serial);
-    }
+    httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
+    strlcat(uristr, optionsstr, sizeof(uristr));
+
+    cupsBackendReport("direct", uristr, make_modelstr, make_modelstr, idstr,
+                          NULL);
+  list_device_done:
 
-    return obj != IO_OBJECT_NULL;
+    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, CFStringRef deviceIDString, UInt32 deviceLocation, UInt8 interfaceNum, UInt8 alternateSetting)
+static Boolean find_device_cb(io_service_t obj, printer_interface_t printerIntf, void *refcon)
 {
-    Boolean keepLooking = true;
+  (void)refcon;
+
+  Boolean keepLooking = true;
 
-    if (obj != IO_OBJECT_NULL)
+  if (obj != IO_OBJECT_NULL)
+  {
+    CFStringRef deviceIDString = NULL;
+    CFStringRef make = NULL;
+    CFStringRef model = NULL;
+    CFStringRef serial = NULL;
+
+    deviceIDString = copy_printer_interface_deviceid(printerIntf, 0);
+    if (deviceIDString == NULL)
+      goto find_device_done;
+
+    make = deviceIDCopyManufacturer(deviceIDString);
+    model = deviceIDCopyModel(deviceIDString);
+    serial = deviceIDCopySerialNumber(deviceIDString);
+
+    if (make && CFStringCompare(make, g.make, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
     {
-        CFStringRef make = deviceIDCopyManufacturer(deviceIDString);
-        CFStringRef model = deviceIDCopyModel(deviceIDString);
-        CFStringRef serial = deviceIDCopySerialNumber(deviceIDString);
+      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 (make && CFStringCompare(make, g.make, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
+        if (intfProtocol == kUSBPrintingProtocolIPP)
+            return keepLooking;
+
+        if (g.serial != NULL && CFStringGetLength(g.serial) > 0)
         {
-            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;
-                        g.location = deviceLocation;
-                        g.alternateSetting = alternateSetting;
-                        keepLooking = false;
-                    }
-                }
-                else
-                {
-                    if (g.printer_obj != 0)
-                        IOObjectRelease(g.printer_obj);
-
-                    g.alternateSetting = alternateSetting;
-                    g.printer_obj = obj;
-                    IOObjectRetain(obj);
-
-                    if (g.location == 0 || g.location == deviceLocation)
-                        keepLooking = false;
-                }
-
-                if ( !keepLooking )
-                    g.interfaceNum = interfaceNum;
-            }
+          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;
+          }
         }
-
-        if (make) CFRelease(make);
-        if (model) CFRelease(model);
-        if (serial) CFRelease(serial);
-    }
-    else
-    {
-        keepLooking = (g.printer_obj == 0);
-        if (obj == IO_OBJECT_NULL && keepLooking)
+        else
         {
-            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;
-            }
+          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 (!keepLooking)
+          g.interfaceNum = intfNumber;
+      }
     }
 
-    if (!keepLooking && g.status_timer != NULL)
+  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 && g.interfaceProtocol != kUSBPrintingProtocolIPP);
+    if (obj == IO_OBJECT_NULL && keepLooking)
     {
-        fputs("STATE: -offline-report\n", stderr);
-        _cupsLangPrintFilter(stderr, "INFO", _("The printer is now online."));
-        CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), g.status_timer, kCFRunLoopDefaultMode);
-        CFRelease(g.status_timer);
-        g.status_timer = NULL;
+      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;
+      }
     }
+  }
+
+  if (!keepLooking && g.status_timer != NULL)
+  {
+    fputs("STATE: -offline-report\n", stderr);
+    _cupsLangPrintFilter(stderr, "INFO", _("The printer is now online."));
+    CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), g.status_timer, kCFRunLoopDefaultMode);
+    CFRelease(g.status_timer);
+    g.status_timer = NULL;
+  }
 
-    return keepLooking;
+  return keepLooking;
 }
 
 static CFStringRef deviceIDCopySerialNumber(CFStringRef deviceID)
@@ -1568,23 +1547,6 @@ static printer_interface_t usb_printer_interface_interface(io_service_t usbClass
        return intf;
 }
 
-static IOUSBDeviceInterface **usb_device_interface_for_device(io_service_t usbDevice)
-{
-       IOUSBDeviceInterface ** intf = NULL;
-       IOCFPlugInInterface **plugin = NULL;
-       SInt32  score;
-
-       int kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score);
-       if (kr == kIOReturnSuccess)
-       {
-               (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (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
@@ -1636,7 +1598,7 @@ static CFStringRef copy_printer_interface_deviceid(printer_interface_t printer,
                /* This request takes the 0 based configuration index. IOKit returns a 1 based configuration index */
                configurationIndex -= 1;
 
-               bzero(&request, sizeof(request));
+               memset(&request, 0, sizeof(request));
 
                request.bmRequestType           = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBInterface);
                request.bRequest                        = kUSBPrintClassGetDeviceID;
@@ -1678,7 +1640,7 @@ static CFStringRef copy_printer_interface_deviceid(printer_interface_t printer,
                IOUSBDevRequestTO               request;
                IOUSBDeviceDescriptor   desc;
 
-               bzero(&request, sizeof(request));
+               memset(&request, 0, sizeof(request));
 
                request.bmRequestType = USBmakebmRequestType( kUSBIn,  kUSBStandard, kUSBDevice );
                request.bRequest = kUSBRqGetDescriptor;
@@ -1707,11 +1669,34 @@ static CFStringRef copy_printer_interface_deviceid(printer_interface_t printer,
                                        CFStringAppendFormat(extras, NULL, CFSTR("MDL:%@;"), model);
                        }
 
-                       if (serial == NULL && desc.iSerialNumber != 0)
+                       if (desc.iSerialNumber != 0)
                        {
-                               serial = copy_printer_interface_indexed_description(printer, desc.iSerialNumber, kUSBLanguageEnglish);
-                               if (serial && CFStringGetLength(serial) > 0)
-                                       CFStringAppendFormat(extras, NULL, CFSTR("SERN:%@;"), serial);
+                               // 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)
@@ -1730,18 +1715,18 @@ static CFStringRef copy_printer_interface_deviceid(printer_interface_t printer,
 
        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);
+               /* 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);
+                       CFMutableStringRef deviceIDString = CFStringCreateMutableCopy(NULL, 0, ret);
+                       CFRelease(ret);
 
-               ret = deviceIDString;
-               CFStringFindAndReplace(deviceIDString, CFSTR("+"), CFSTR(""), range, 0);
-       }
+                       ret = deviceIDString;
+                       CFStringFindAndReplace(deviceIDString, CFSTR("+"), CFSTR(""), range, 0);
+               }
        }
 
        if (manufacturer != NULL)
@@ -1768,7 +1753,7 @@ static CFStringRef copy_printer_interface_indexed_description(printer_interface_
        UInt8 description[256]; // Max possible descriptor length
        IOUSBDevRequestTO       request;
 
-       bzero(description, 2);
+       memset(description, 0, 2);
 
        request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
        request.bRequest = kUSBRqGetDescriptor;
@@ -1782,7 +1767,7 @@ static CFStringRef copy_printer_interface_indexed_description(printer_interface_
        err = (*printer)->ControlRequestTO(printer, 0, &request);
        if (err != kIOReturnSuccess && err != kIOReturnOverrun)
        {
-               bzero(description, request.wLength);
+               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
@@ -1815,7 +1800,7 @@ static CFStringRef copy_printer_interface_indexed_description(printer_interface_
        request.wValue = (kUSBStringDesc << 8) | index;
        request.wIndex = language;
 
-       bzero(description, length);
+       memset(description, 0, length);
        request.wLength = (UInt16)length;
        request.pData = &description;
        request.completionTimeout = 0;
@@ -2049,7 +2034,7 @@ static void parse_options(char *options,
                             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 = (UInt32)strtoul(value, NULL, 16);
   }
@@ -2093,11 +2078,11 @@ static void setup_cfLanguage(void)
 }
 
 #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().
  *
@@ -2116,23 +2101,17 @@ static void run_legacy_backend(int argc,
 
 
  /*
-  * 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)
   {
-    log_usb_class_driver(IS_NOT_64BIT);
-
    /*
     * Setup a SIGTERM handler then block it before forking...
     */
@@ -2158,21 +2137,13 @@ static void run_legacy_backend(int argc,
     * 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;
 
@@ -2181,11 +2152,7 @@ static void run_legacy_backend(int argc,
       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);
@@ -2259,8 +2226,6 @@ static void run_legacy_backend(int argc,
 
   exit(exitstatus);
 }
-#endif /* __i386__ || __x86_64__ */
-
 
 /*
  * 'sigterm_handler()' - SIGTERM handler.
@@ -2269,7 +2234,6 @@ static void run_legacy_backend(int argc,
 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...
   */
@@ -2291,12 +2255,12 @@ sigterm_handler(int sig)                /* I - Signal */
       _exit(0);
     else
     {
-      write(2, "DEBUG: Child crashed.\n", 22);
+      backendMessage("DEBUG: Child crashed.\n");
       _exit(CUPS_BACKEND_STOP);
     }
   }
-#endif /* __i386__ || __x86_64__ */
 }
+#endif /* __arm64e__ */
 
 
 /*
@@ -2509,34 +2473,3 @@ static void get_device_id(cups_sc_status_t *status,
 
   *status  = CUPS_SC_STATUS_OK;
 }
-
-
-static void
-log_usb_class_driver(int is_64bit)     /* I - Is the USB class driver 64-bit? */
-{
- /*
-  * Report the usage of legacy USB class drivers to Apple if the user opts into providing
-  * feedback to Apple...
-  */
-
-  aslmsg aslm = asl_new(ASL_TYPE_MSG);
-  if (aslm)
-  {
-    ppd_file_t *ppd = ppdOpenFile(getenv("PPD"));
-    const char *make_model = ppd ? ppd->nickname : NULL;
-    ppd_attr_t *version = ppdFindAttr(ppd, "FileVersion", "");
-
-    asl_set(aslm, "com.apple.message.domain", "com.apple.printing.usb.64bit");
-    asl_set(aslm, "com.apple.message.result", is_64bit ? "yes" : "no");
-    asl_set(aslm, "com.apple.message.signature", make_model ? make_model : "Unknown");
-    asl_set(aslm, "com.apple.message.signature2", version ? version->value : "?.?");
-    asl_set(aslm, "com.apple.message.summarize", "YES");
-    asl_log(NULL, aslm, ASL_LEVEL_NOTICE, "");
-    asl_free(aslm);
-  }
-}
-
-
-/*
- * End of "$Id$".
- */