Report USB device disconnection when detected

USB device disconnection is detected via a hotplug callback when it is
supported.

In addition, report disconnection on libusb calls returning
LIBUSB_ERROR_NO_DEVICE or LIBUSB_ERROR_NOT_FOUND. This allows to detect
disconnection after a libusb call when hotplug is not available.

PR #3011 <https://github.com/Genymobile/scrcpy/pull/3011>
This commit is contained in:
Romain Vimont 2022-02-10 07:57:18 +01:00
parent 3ee3f8dc02
commit be1936bb85
3 changed files with 30 additions and 2 deletions

View file

@ -95,6 +95,7 @@ sc_aoa_register_hid(struct sc_aoa *aoa, uint16_t accessory_id,
DEFAULT_TIMEOUT); DEFAULT_TIMEOUT);
if (result < 0) { if (result < 0) {
LOGE("REGISTER_HID: libusb error: %s", libusb_strerror(result)); LOGE("REGISTER_HID: libusb error: %s", libusb_strerror(result));
sc_usb_check_disconnected(aoa->usb, result);
return false; return false;
} }
@ -131,6 +132,7 @@ sc_aoa_set_hid_report_desc(struct sc_aoa *aoa, uint16_t accessory_id,
DEFAULT_TIMEOUT); DEFAULT_TIMEOUT);
if (result < 0) { if (result < 0) {
LOGE("SET_HID_REPORT_DESC: libusb error: %s", libusb_strerror(result)); LOGE("SET_HID_REPORT_DESC: libusb error: %s", libusb_strerror(result));
sc_usb_check_disconnected(aoa->usb, result);
return false; return false;
} }
@ -173,6 +175,7 @@ sc_aoa_send_hid_event(struct sc_aoa *aoa, const struct sc_hid_event *event) {
DEFAULT_TIMEOUT); DEFAULT_TIMEOUT);
if (result < 0) { if (result < 0) {
LOGE("SEND_HID_EVENT: libusb error: %s", libusb_strerror(result)); LOGE("SEND_HID_EVENT: libusb error: %s", libusb_strerror(result));
sc_usb_check_disconnected(aoa->usb, result);
return false; return false;
} }
@ -195,6 +198,7 @@ sc_aoa_unregister_hid(struct sc_aoa *aoa, const uint16_t accessory_id) {
DEFAULT_TIMEOUT); DEFAULT_TIMEOUT);
if (result < 0) { if (result < 0) {
LOGE("UNREGISTER_HID: libusb error: %s", libusb_strerror(result)); LOGE("UNREGISTER_HID: libusb error: %s", libusb_strerror(result));
sc_usb_check_disconnected(aoa->usb, result);
return false; return false;
} }

View file

@ -216,6 +216,24 @@ sc_usb_destroy(struct sc_usb *usb) {
libusb_exit(usb->context); libusb_exit(usb->context);
} }
static void
sc_usb_report_disconnected(struct sc_usb *usb) {
if (usb->cbs && !atomic_flag_test_and_set(&usb->disconnection_notified)) {
assert(usb->cbs && usb->cbs->on_disconnected);
usb->cbs->on_disconnected(usb, usb->cbs_userdata);
}
}
bool
sc_usb_check_disconnected(struct sc_usb *usb, int result) {
if (result == LIBUSB_ERROR_NO_DEVICE || result == LIBUSB_ERROR_NOT_FOUND) {
sc_usb_report_disconnected(usb);
return false;
}
return true;
}
static int static int
sc_usb_libusb_callback(libusb_context *ctx, libusb_device *device, sc_usb_libusb_callback(libusb_context *ctx, libusb_device *device,
libusb_hotplug_event event, void *userdata) { libusb_hotplug_event event, void *userdata) {
@ -232,8 +250,7 @@ sc_usb_libusb_callback(libusb_context *ctx, libusb_device *device,
return 0; return 0;
} }
assert(usb->cbs && usb->cbs->on_disconnected); sc_usb_report_disconnected(usb);
usb->cbs->on_disconnected(usb, usb->cbs_userdata);
// Do not automatically deregister the callback by returning 1. Instead, // Do not automatically deregister the callback by returning 1. Instead,
// manually deregister to interrupt libusb_handle_events() from the libusb // manually deregister to interrupt libusb_handle_events() from the libusb
@ -307,6 +324,7 @@ sc_usb_connect(struct sc_usb *usb, libusb_device *device,
if (cbs) { if (cbs) {
atomic_init(&usb->stopped, false); atomic_init(&usb->stopped, false);
usb->disconnection_notified = (atomic_flag) ATOMIC_FLAG_INIT;
if (sc_usb_register_callback(usb)) { if (sc_usb_register_callback(usb)) {
// Create a thread to process libusb events, so that device // Create a thread to process libusb events, so that device
// disconnection could be detected immediately // disconnection could be detected immediately

View file

@ -22,6 +22,7 @@ struct sc_usb {
sc_thread libusb_event_thread; sc_thread libusb_event_thread;
atomic_bool stopped; // only used if cbs != NULL atomic_bool stopped; // only used if cbs != NULL
atomic_flag disconnection_notified;
}; };
struct sc_usb_callbacks { struct sc_usb_callbacks {
@ -73,6 +74,11 @@ sc_usb_connect(struct sc_usb *usb, libusb_device *device,
void void
sc_usb_disconnect(struct sc_usb *usb); sc_usb_disconnect(struct sc_usb *usb);
// A client should call this function with the return value of a libusb call
// to detect disconnection immediately
bool
sc_usb_check_disconnected(struct sc_usb *usb, int result);
void void
sc_usb_stop(struct sc_usb *usb); sc_usb_stop(struct sc_usb *usb);