Skip to content

camera-firmware: fix firmware upload on macOS - #518

Open
gabrielrlima wants to merge 1 commit into
thp:masterfrom
gabrielrlima:macos-camera-firmware-fixes
Open

camera-firmware: fix firmware upload on macOS#518
gabrielrlima wants to merge 1 commit into
thp:masterfrom
gabrielrlima:macos-camera-firmware-fixes

Conversation

@gabrielrlima

Copy link
Copy Markdown

psmove camera-firmware was 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 to libusb_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 subsequent libusb_set_configuration() failed with LIBUSB_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 a set_configuration failure there, since AppleUSBHostCompositeDevice already selects configuration 1.

Testing

Apple Silicon (M4, macOS 26), Sony PS5 HD Camera (CFI-ZEY1) behind a USB 3 hub:

  • Before: segfault on psmove camera-firmware; with only the NULL check fixed, upload aborted with res = -4 at libusb_set_configuration.
  • After both fixes: firmware upload completes ("Firmware uploaded") and the camera re-enumerates as a standard UVC device (05a9:058c, "USB Camera-OV580"), working in Photo Booth, QuickTime and Teams at 1920x1080@30.
  • Linux/Windows code paths are unchanged (the guards only affect macOS behavior).

🤖 Generated with Claude Code

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)) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now #524

Comment on lines +107 to +121
#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

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the libusb_exit() hang, there's now #525

@thp thp left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants