camera-firmware: fix firmware upload on macOS - #518
Conversation
Two fixes for the Darwin libusb backend, which made 'psmove camera-firmware' unusable on macOS: - libusb_get_parent() can return NULL on macOS. The unchecked result was passed to libusb_get_device_descriptor(), crashing with a segfault before the firmware upload could even start. - libusb_reset_device() on macOS triggers a re-enumeration that drops the device off the bus and invalidates the handle, so the following libusb_set_configuration() failed with LIBUSB_ERROR_NO_DEVICE (-4) and aborted the upload. Skip the reset on macOS (the device is freshly enumerated in boot mode anyway) and tolerate a set_configuration failure there, since AppleUSBHostCompositeDevice already selects configuration 1. Tested on Apple Silicon (M4, macOS 26) with a PS5 camera (CFI-ZEY1) behind a USB 3 hub: firmware upload completes and the camera re-enumerates as a standard UVC device (05a9:058c, "USB Camera-OV580") usable in Photo Booth, QuickTime, Teams, etc. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| } | ||
|
|
||
| if (PS4_TO_PS5_ADAPTER_ID.matches(pdesc)) { | ||
| if (parent_dev != nullptr && PS4_TO_PS5_ADAPTER_ID.matches(pdesc)) { |
There was a problem hiding this comment.
The parent_dev != nullptr check is also in line 237 above, can be combined, and pdesc scan be scoped in the if block that has checked parent_dev != nullptr already.
| #if !defined(__APPLE__) | ||
| // On macOS, libusb_reset_device() triggers a re-enumeration that drops | ||
| // the device off the bus and invalidates the handle, so skip it there. | ||
| PSMOVE_VERIFY((res = libusb_reset_device(handle)) == 0, "res = %d", res); | ||
| PSMOVE_VERIFY((res = libusb_set_configuration(handle, 1)) == 0, "res = %d", res); | ||
| #endif | ||
| res = libusb_set_configuration(handle, 1); | ||
| #if defined(__APPLE__) | ||
| // macOS already selects configuration 1 via AppleUSBHostCompositeDevice; | ||
| // tolerate a set_configuration failure as long as we can claim interface 0. | ||
| if (res != 0) { | ||
| PSMOVE_WARNING("libusb_set_configuration failed (res = %d), continuing", res); | ||
| } | ||
| #else | ||
| PSMOVE_VERIFY(res == 0, "res = %d", res); | ||
| #endif |
There was a problem hiding this comment.
Maybe this becomes clearer if there's only a single #if defined(__APPLE__) and an else branch instead of two separated by the libusb_set_configuration() call, especially since it seems like the call isn't necessary (or is it?) on macOS systems?
There was a problem hiding this comment.
I wasn't able to reproduce the issue you were seeing in macOS 26.6 on a 2021 M1 Max MacBook Pro.
The only problem that sporadically happens is that the call to libusb_exit() hangs (possibly to be expected, with the device disconnecting and us not calling libusb_close()), but that seems to not be an issue, as the camera already enumerated as UVC device, and Ctrl+C'ing the process works around the hang. If we know the tool is always called as command-line utility, it would probably be fine to skip the call to libusb_exit() and just let the operating system take care of cleaning up after us.
I tried connecting both ways:
- PS5 camera directly (via USB-C-to-USB-A-3.0 adapter) on the MacBook Pro
- PS5 camera via a USB 3.0 hub (and that via USB-C-to-USB-A-3.0 adapter) on the MacBook Pro
The firmware file I'm using has a SHA-1 hash of 0fa4da31a12b662a9a80abc8b84932770df8f7e1.
A subsequent run of psmove test-camera (making sure PSMOVE_USE_PS3EYE_DRIVER=OFF in CMake) properly uses the camera and crops its image accordingly.
psmove camera-firmwarewas unusable on macOS due to two issues with the Darwin libusb backend:1. Segfault from NULL parent device
libusb_get_parent()can return NULL on macOS. The result was passed unchecked tolibusb_get_device_descriptor(), crashing the tool before the firmware upload could even start.2. Upload aborted after device reset
libusb_reset_device()on the Darwin backend triggers a re-enumeration that drops the device off the bus and invalidates the handle, so the subsequentlibusb_set_configuration()failed withLIBUSB_ERROR_NO_DEVICE(-4) and aborted the upload. This change skips the reset on macOS (the device is freshly enumerated in boot mode anyway) and tolerates aset_configurationfailure there, sinceAppleUSBHostCompositeDevicealready selects configuration 1.Testing
Apple Silicon (M4, macOS 26), Sony PS5 HD Camera (CFI-ZEY1) behind a USB 3 hub:
psmove camera-firmware; with only the NULL check fixed, upload aborted withres = -4atlibusb_set_configuration.05a9:058c, "USB Camera-OV580"), working in Photo Booth, QuickTime and Teams at 1920x1080@30.🤖 Generated with Claude Code