diff --git a/app/meson.build b/app/meson.build index c26332e0..5497281a 100644 --- a/app/meson.build +++ b/app/meson.build @@ -78,6 +78,7 @@ if usb_support 'src/usb/aoa_hid.c', 'src/usb/hid_keyboard.c', 'src/usb/hid_mouse.c', + 'src/usb/usb.c', ] endif diff --git a/app/src/usb/aoa_hid.c b/app/src/usb/aoa_hid.c index a9460c3b..b03808ae 100644 --- a/app/src/usb/aoa_hid.c +++ b/app/src/usb/aoa_hid.c @@ -50,74 +50,6 @@ log_libusb_error(enum libusb_error errcode) { LOGW("libusb error: %s", libusb_strerror(errcode)); } -static bool -accept_device(libusb_device *device, const char *serial) { - // do not log any USB error in this function, it is expected that many USB - // devices available on the computer have permission restrictions - - struct libusb_device_descriptor desc; - int result = libusb_get_device_descriptor(device, &desc); - if (result < 0 || !desc.iSerialNumber) { - return false; - } - - libusb_device_handle *handle; - result = libusb_open(device, &handle); - if (result < 0) { - return false; - } - - char buffer[128]; - result = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, - (unsigned char *) buffer, - sizeof(buffer)); - libusb_close(handle); - if (result < 0) { - return false; - } - - buffer[sizeof(buffer) - 1] = '\0'; // just in case - - // accept the device if its serial matches - return !strcmp(buffer, serial); -} - -static libusb_device * -sc_aoa_find_usb_device(const char *serial) { - if (!serial) { - return NULL; - } - - libusb_device **list; - libusb_device *result = NULL; - ssize_t count = libusb_get_device_list(NULL, &list); - if (count < 0) { - log_libusb_error((enum libusb_error) count); - return NULL; - } - - for (size_t i = 0; i < (size_t) count; ++i) { - libusb_device *device = list[i]; - - if (accept_device(device, serial)) { - result = libusb_ref_device(device); - break; - } - } - libusb_free_device_list(list, 1); - return result; -} - -static int -sc_aoa_open_usb_handle(libusb_device *device, libusb_device_handle **handle) { - int result = libusb_open(device, handle); - if (result < 0) { - log_libusb_error((enum libusb_error) result); - return result; - } - return 0; -} - bool sc_aoa_init(struct sc_aoa *aoa, const char *serial, struct sc_acksync *acksync) { @@ -133,31 +65,16 @@ sc_aoa_init(struct sc_aoa *aoa, const char *serial, goto error_destroy_mutex; } - if (libusb_init(&aoa->usb_context) != LIBUSB_SUCCESS) { + bool ok = sc_usb_init(&aoa->usb, serial); + if (!ok) { goto error_destroy_cond; } - aoa->usb_device = sc_aoa_find_usb_device(serial); - if (!aoa->usb_device) { - LOGW("USB device of serial %s not found", serial); - goto error_exit_libusb; - } - - if (sc_aoa_open_usb_handle(aoa->usb_device, &aoa->usb_handle) < 0) { - LOGW("Open USB handle failed"); - goto error_unref_device; - return false; - } - aoa->stopped = false; aoa->acksync = acksync; return true; -error_unref_device: - libusb_unref_device(aoa->usb_device); -error_exit_libusb: - libusb_exit(aoa->usb_context); error_destroy_cond: sc_cond_destroy(&aoa->event_cond); error_destroy_mutex: @@ -173,9 +90,7 @@ sc_aoa_destroy(struct sc_aoa *aoa) { sc_hid_event_destroy(&event); } - libusb_close(aoa->usb_handle); - libusb_unref_device(aoa->usb_device); - libusb_exit(aoa->usb_context); + sc_usb_destroy(&aoa->usb); sc_cond_destroy(&aoa->event_cond); sc_mutex_destroy(&aoa->mutex); } @@ -192,7 +107,7 @@ sc_aoa_register_hid(struct sc_aoa *aoa, uint16_t accessory_id, uint16_t index = report_desc_size; unsigned char *buffer = NULL; uint16_t length = 0; - int result = libusb_control_transfer(aoa->usb_handle, request_type, request, + int result = libusb_control_transfer(aoa->usb.handle, request_type, request, value, index, buffer, length, DEFAULT_TIMEOUT); if (result < 0) { @@ -228,7 +143,7 @@ sc_aoa_set_hid_report_desc(struct sc_aoa *aoa, uint16_t accessory_id, // libusb_control_transfer expects a pointer to non-const unsigned char *buffer = (unsigned char *) report_desc; uint16_t length = report_desc_size; - int result = libusb_control_transfer(aoa->usb_handle, request_type, request, + int result = libusb_control_transfer(aoa->usb.handle, request_type, request, value, index, buffer, length, DEFAULT_TIMEOUT); if (result < 0) { @@ -270,7 +185,7 @@ sc_aoa_send_hid_event(struct sc_aoa *aoa, const struct sc_hid_event *event) { uint16_t index = 0; unsigned char *buffer = event->buffer; uint16_t length = event->size; - int result = libusb_control_transfer(aoa->usb_handle, request_type, request, + int result = libusb_control_transfer(aoa->usb.handle, request_type, request, value, index, buffer, length, DEFAULT_TIMEOUT); if (result < 0) { @@ -292,7 +207,7 @@ sc_aoa_unregister_hid(struct sc_aoa *aoa, const uint16_t accessory_id) { uint16_t index = 0; unsigned char *buffer = NULL; uint16_t length = 0; - int result = libusb_control_transfer(aoa->usb_handle, request_type, request, + int result = libusb_control_transfer(aoa->usb.handle, request_type, request, value, index, buffer, length, DEFAULT_TIMEOUT); if (result < 0) { diff --git a/app/src/usb/aoa_hid.h b/app/src/usb/aoa_hid.h index e8fb9708..0ce78626 100644 --- a/app/src/usb/aoa_hid.h +++ b/app/src/usb/aoa_hid.h @@ -6,6 +6,7 @@ #include +#include "usb.h" #include "util/acksync.h" #include "util/cbuf.h" #include "util/thread.h" @@ -29,9 +30,7 @@ sc_hid_event_destroy(struct sc_hid_event *hid_event); struct sc_hid_event_queue CBUF(struct sc_hid_event, 64); struct sc_aoa { - libusb_context *usb_context; - libusb_device *usb_device; - libusb_device_handle *usb_handle; + struct sc_usb usb; sc_thread thread; sc_mutex mutex; sc_cond event_cond; diff --git a/app/src/usb/usb.c b/app/src/usb/usb.c new file mode 100644 index 00000000..e933fdbc --- /dev/null +++ b/app/src/usb/usb.c @@ -0,0 +1,112 @@ +#include "usb.h" + +#include + +#include "util/log.h" + +static inline void +log_libusb_error(enum libusb_error errcode) { + LOGW("libusb error: %s", libusb_strerror(errcode)); +} + +static bool +accept_device(libusb_device *device, const char *serial) { + // Do not log any USB error in this function, it is expected that many USB + // devices available on the computer have permission restrictions + + struct libusb_device_descriptor desc; + int result = libusb_get_device_descriptor(device, &desc); + if (result < 0 || !desc.iSerialNumber) { + return false; + } + + libusb_device_handle *handle; + result = libusb_open(device, &handle); + if (result < 0) { + return false; + } + + char buffer[128]; + result = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, + (unsigned char *) buffer, + sizeof(buffer)); + libusb_close(handle); + if (result < 0) { + return false; + } + + buffer[sizeof(buffer) - 1] = '\0'; // just in case + + // Accept the device if its serial matches + return !strcmp(buffer, serial); +} + +static libusb_device * +sc_usb_find_device(const char *serial) { + if (!serial) { + return NULL; + } + + libusb_device **list; + libusb_device *result = NULL; + ssize_t count = libusb_get_device_list(NULL, &list); + if (count < 0) { + log_libusb_error((enum libusb_error) count); + return NULL; + } + + for (size_t i = 0; i < (size_t) count; ++i) { + libusb_device *device = list[i]; + + if (accept_device(device, serial)) { + result = libusb_ref_device(device); + break; + } + } + + libusb_free_device_list(list, 1); + return result; +} + +static libusb_device_handle * +sc_usb_open_handle(libusb_device *device) { + libusb_device_handle *handle; + int result = libusb_open(device, &handle); + if (result < 0) { + log_libusb_error((enum libusb_error) result); + return NULL; + } + return handle; + } + +bool +sc_usb_init(struct sc_usb *usb, const char *serial) { + // There is only one device, initialize the context here + if (libusb_init(&usb->context) != LIBUSB_SUCCESS) { + return false; + } + + usb->device = sc_usb_find_device(serial); + if (!usb->device) { + LOGW("USB device %s not found", serial); + libusb_exit(usb->context); + return false; + } + + usb->handle = sc_usb_open_handle(usb->device); + if (!usb->handle) { + LOGW("Could not open USB device %s", serial); + libusb_unref_device(usb->device); + libusb_exit(usb->context); + return false; + } + + return true; +} + +void +sc_usb_destroy(struct sc_usb *usb) { + libusb_close(usb->handle); + libusb_unref_device(usb->device); + libusb_exit(usb->context); +} diff --git a/app/src/usb/usb.h b/app/src/usb/usb.h new file mode 100644 index 00000000..5743626d --- /dev/null +++ b/app/src/usb/usb.h @@ -0,0 +1,21 @@ +#ifndef SC_USB_H +#define SC_USB_H + +#include "common.h" + +#include +#include + +struct sc_usb { + libusb_context *context; + libusb_device *device; + libusb_device_handle *handle; +}; + +bool +sc_usb_init(struct sc_usb *usb, const char *serial); + +void +sc_usb_destroy(struct sc_usb *usb); + +#endif