summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/usb.c88
1 files changed, 73 insertions, 15 deletions
diff --git a/src/usb.c b/src/usb.c
index ee64fa5..c98b58a 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -390,6 +390,71 @@ static struct usb_device* find_device(int bus, int address)
390 return NULL; 390 return NULL;
391} 391}
392 392
393/// @brief guess the current mode
394/// @param dev
395/// @param usbdev
396/// @param handle
397/// @return 0 - undetermined, 1 - initial, 2 - valeria, 3 - cdc_ncm
398static int guess_mode(struct libusb_device* dev, struct usb_device *usbdev)
399{
400 int res, j;
401 int has_valeria = 0, has_cdc_ncm = 0, has_usbmux = 0;
402 struct libusb_device_descriptor devdesc = usbdev->devdesc;
403 struct libusb_config_descriptor *config;
404 int bus = usbdev->bus;
405 int address = usbdev->address;
406
407 if(devdesc.bNumConfigurations <= 4) {
408 // Assume this is initial mode
409 return 1;
410 }
411
412 if(devdesc.bNumConfigurations != 5) {
413 // No known modes with more then 5 configurations
414 return 0;
415 }
416
417 if((res = libusb_get_config_descriptor_by_value(dev, 5, &config)) != 0) {
418 usbmuxd_log(LL_NOTICE, "Could not get configuration 5 descriptor for device %i-%i: %s", bus, address, libusb_error_name(res));
419 return 0;
420 }
421
422 // Require both usbmux and one of the other interfaces to determine this is a valid configuration
423 for(j = 0 ; j < config->bNumInterfaces ; j++) {
424 const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0];
425 if(intf->bInterfaceClass == INTERFACE_CLASS &&
426 intf->bInterfaceSubClass == 42 &&
427 intf->bInterfaceProtocol == 255) {
428 has_valeria = 1;
429 }
430 // https://github.com/torvalds/linux/blob/72a85e2b0a1e1e6fb4ee51ae902730212b2de25c/include/uapi/linux/usb/cdc.h#L22
431 // 2 for Communication class, 0xd for CDC NCM subclass
432 if(intf->bInterfaceClass == 2 &&
433 intf->bInterfaceSubClass == 0xd) {
434 has_cdc_ncm = 1;
435 }
436 if(intf->bInterfaceClass == INTERFACE_CLASS &&
437 intf->bInterfaceSubClass == INTERFACE_SUBCLASS &&
438 intf->bInterfaceProtocol == INTERFACE_PROTOCOL) {
439 has_usbmux = 1;
440 }
441 }
442
443 libusb_free_config_descriptor(config);
444
445 if(has_valeria && has_usbmux) {
446 usbmuxd_log(LL_NOTICE, "Found Valeria and Apple USB Multiplexor in device %i-%i configuration 5", bus, address);
447 return 2;
448 }
449
450 if(has_cdc_ncm && has_usbmux) {
451 usbmuxd_log(LL_NOTICE, "Found CDC-NCM and Apple USB Multiplexor in device %i-%i configuration 5", bus, address);
452 return 3;
453 }
454
455 return 0;
456}
457
393/// @brief Finds and sets the valid configuration, interface and endpoints on the usb_device 458/// @brief Finds and sets the valid configuration, interface and endpoints on the usb_device
394static int set_valid_configuration(struct libusb_device* dev, struct usb_device *usbdev, struct libusb_device_handle *handle) 459static int set_valid_configuration(struct libusb_device* dev, struct usb_device *usbdev, struct libusb_device_handle *handle)
395{ 460{
@@ -625,25 +690,19 @@ static void get_mode_cb(struct libusb_transfer* transfer)
625 690
626 unsigned char *data = libusb_control_transfer_get_data(transfer); 691 unsigned char *data = libusb_control_transfer_get_data(transfer);
627 692
628 char* desired_mode = getenv(ENV_DEVICE_MODE); 693 int desired_mode = atoi(getenv(ENV_DEVICE_MODE));
629 if(!desired_mode) { 694 int guessed_mode = guess_mode(context->dev, dev);
630 context->wIndex = 0x1; 695
631 }
632 else if(!strncmp(desired_mode, "2", 1)) {
633 context->wIndex = 0x2;
634 }
635 else if(!strncmp(desired_mode, "3", 1)) {
636 context->wIndex = 0x3;
637 }
638 // Response is 3:3:3:0 for initial mode, 5:3:3:0 otherwise. 696 // Response is 3:3:3:0 for initial mode, 5:3:3:0 otherwise.
639 // In later commit, should infer the mode from available configurations and interfaces.
640 usbmuxd_log(LL_INFO, "Received response %i:%i:%i:%i for get_mode request for device %i-%i", data[0], data[1], data[2], data[3], context->bus, context->address); 697 usbmuxd_log(LL_INFO, "Received response %i:%i:%i:%i for get_mode request for device %i-%i", data[0], data[1], data[2], data[3], context->bus, context->address);
641 if(context->wIndex > 1 && data[0] == 3 && data[1] == 3 && data[2] == 3 && data[3] == 0) { 698 if(desired_mode >= 1 && desired_mode <= 3 &&
642 // 3:3:3:0 means the initial mode 699 guessed_mode > 0 && // do not switch mode if guess failed
700 guessed_mode != desired_mode) {
643 usbmuxd_log(LL_WARNING, "Switching device %i-%i mode to %i", context->bus, context->address, context->wIndex); 701 usbmuxd_log(LL_WARNING, "Switching device %i-%i mode to %i", context->bus, context->address, context->wIndex);
644 702
645 context->bRequest = APPLE_VEND_SPECIFIC_SET_MODE; 703 context->bRequest = APPLE_VEND_SPECIFIC_SET_MODE;
646 context->wValue = 0; 704 context->wValue = 0;
705 context->wIndex = desired_mode;
647 context->wLength = 1; 706 context->wLength = 1;
648 707
649 if((res = submit_vendor_specific(transfer->dev_handle, context, switch_mode_cb)) != 0) { 708 if((res = submit_vendor_specific(transfer->dev_handle, context, switch_mode_cb)) != 0) {
@@ -653,8 +712,7 @@ static void get_mode_cb(struct libusb_transfer* transfer)
653 } 712 }
654 } 713 }
655 else { 714 else {
656 // in other modes, usually 5:3:3:0 (but in any other unexpected case as well), complete init: 715 usbmuxd_log(LL_WARNING, "Skipping switch device %i-%i mode from %i to %i", context->bus, context->address, guessed_mode, desired_mode);
657 usbmuxd_log(LL_WARNING, "Skipping switch device %i-%i mode", context->bus, context->address);
658 device_complete_initialization(context, transfer->dev_handle); 716 device_complete_initialization(context, transfer->dev_handle);
659 free(context); 717 free(context);
660 } 718 }