--- backend/usb-darwin.c 2026-04-28 01:13:21.000000000 +0800 +++ backend/usb-darwin.c 2026-06-08 21:20:30.000000000 +0800 @@ -73,13 +73,13 @@ #include #include #include +#include -/* - * Include necessary headers. - */ - -extern char **environ; +#define environ (*_NSGetEnviron()) +#ifndef kIOMainPortDefault +#define kIOMainPortDefault kIOMasterPortDefault +#endif /* * DEBUG_WRITES, if defined, causes the backend to write data to the printer in @@ -1549,6 +1549,32 @@ return intf; } +typedef struct { + IOUSBDevRequestTO request; + printer_interface_t printer; +} send_request_ctx_t; + +static IOReturn +send_device_id_request(send_request_ctx_t *ctx, size_t size) +{ + char *buffer; + + if (ctx->request.pData) + { + free(ctx->request.pData); + ctx->request.wLength = 0; + ctx->request.pData = NULL; + } + + buffer = malloc(size); + if (buffer == NULL) + return kIOReturnNoMemory; + + ctx->request.wLength = HostToUSBWord(size); + ctx->request.pData = buffer; + return (*ctx->printer)->ControlRequestTO(ctx->printer, 0, &ctx->request); +} + 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 @@ -1576,62 +1602,47 @@ 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; - } + send_request_ctx_t ctx; - IOReturn berr = kIOReturnError; - char *buffer = malloc(size); - if (buffer == NULL) - return kIOReturnNoMemory; - - request.wLength = HostToUSBWord(size); - request.pData = buffer; - berr = (*printer)->ControlRequestTO(printer, 0, &request); - return berr; - }; + /* IOKit returns 1-based configuration index; request wants 0-based */ + configurationIndex -= 1; - /* This request takes the 0 based configuration index. IOKit returns a 1 based configuration index */ - configurationIndex -= 1; - - memset(&request, 0, sizeof(request)); + memset(&ctx, 0, sizeof(ctx)); + ctx.printer = printer; - 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 + ctx.request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBInterface); + ctx.request.bRequest = kUSBPrintClassGetDeviceID; + ctx.request.wValue = HostToUSBWord(configurationIndex); + ctx.request.wIndex = HostToUSBWord(pack_device_id_wIndex(interfaceNumber, alternateSetting)); + ctx.request.noDataTimeout = kDefaultNoDataTimeout; + ctx.request.completionTimeout = 0; // Copying behavior from Generic Class Driver - err = sendRequest(bufferLength); + err = send_device_id_request(&ctx, bufferLength); - if (err == kIOReturnSuccess && request.wLenDone > 1) - { - UInt16 actualLength = OSSwapBigToHostInt16(*((UInt16 *)request.pData)); + if (err == kIOReturnSuccess && ctx.request.wLenDone > 1) + { + UInt16 actualLength = OSSwapBigToHostInt16(*((UInt16 *)ctx.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 (actualLength > 2 && actualLength <= bufferLength - 2) + { + ret = CFStringCreateWithBytes(NULL, (const UInt8 *)ctx.request.pData + 2, + actualLength - 2, kCFStringEncodingUTF8, false); + } + else if (actualLength > 2) + { + err = send_device_id_request(&ctx, actualLength); + if (err == kIOReturnSuccess && ctx.request.wLenDone > 0) + { + actualLength = OSSwapBigToHostInt16(*((UInt16 *)ctx.request.pData)); + ret = CFStringCreateWithBytes(NULL, (const UInt8 *)ctx.request.pData + 2, + actualLength - 2, kCFStringEncodingUTF8, false); + } + } + } - if (request.pData) - free(request.pData); - } + if (ctx.request.pData) + free(ctx.request.pData); + } CFStringRef manufacturer = deviceIDCopyManufacturer(ret); CFStringRef model = deviceIDCopyModel(ret);