diff options
author | 2022-12-23 12:42:50 +0200 | |
---|---|---|
committer | 2022-12-23 12:42:50 +0200 | |
commit | a2cbb595276a328e50c2723fbe3cba8a8099dea0 (patch) | |
tree | cc9415c36e8f497966939b2156f90de2c7fc7a70 | |
parent | 1eb5a01477da3a29803ce5602c85e9e98e4a4b72 (diff) | |
download | usbmuxd-a2cbb595276a328e50c2723fbe3cba8a8099dea0.tar.gz usbmuxd-a2cbb595276a328e50c2723fbe3cba8a8099dea0.tar.bz2 |
Simplify finding valid configuration, interface and endpoints and refactor to a separate function.
This function can later be used to determine active mode.
-rw-r--r-- | src/usb.c | 186 |
1 files changed, 87 insertions, 99 deletions
@@ -390,132 +390,120 @@ static struct usb_device* find_device(int bus, int address) | |||
390 | return NULL; | 390 | return NULL; |
391 | } | 391 | } |
392 | 392 | ||
393 | static void device_complete_initialization(struct mode_context *context, struct libusb_device_handle *handle) | 393 | /// @brief Finds and sets the valid configuration, interface and endpoints on the usb_device |
394 | static int set_valid_configuration(struct libusb_device* dev, struct usb_device *usbdev, struct libusb_device_handle *handle) | ||
394 | { | 395 | { |
395 | struct usb_device *usbdev = find_device(context->bus, context->address); | 396 | int j, k, res, found = 0; |
396 | if(!usbdev) { | 397 | struct libusb_config_descriptor *config; |
397 | usbmuxd_log(LL_ERROR, "Device %d-%d is missing from device list, aborting initialization", context->bus, context->address); | 398 | const struct libusb_interface_descriptor *intf; |
398 | return; | ||
399 | } | ||
400 | struct libusb_device *dev = context->dev; | ||
401 | struct libusb_device_descriptor devdesc = usbdev->devdesc; | 399 | struct libusb_device_descriptor devdesc = usbdev->devdesc; |
402 | int bus = context->bus; | 400 | int bus = usbdev->bus; |
403 | int address = context->address; | 401 | int address = usbdev->address; |
404 | int desired_config = devdesc.bNumConfigurations; | 402 | int current_config = 0; |
405 | int j, res; | 403 | |
406 | struct libusb_transfer *transfer; | 404 | if((res = libusb_get_configuration(handle, ¤t_config)) != 0) { |
405 | usbmuxd_log(LL_WARNING, "Could not get current configuration for device %d-%d: %s", bus, address, libusb_error_name(res)); | ||
406 | return -1; | ||
407 | } | ||
407 | 408 | ||
408 | if(desired_config > 4) { | 409 | for(j = devdesc.bNumConfigurations ; j > 0 ; j--) { |
409 | if(desired_config > 5) { | 410 | if((res = libusb_get_config_descriptor_by_value(dev, j, &config)) != 0) { |
410 | usbmuxd_log(LL_ERROR, "Device %d-%d has more than 5 configurations, but usbmuxd doesn't support that. Choosing configuration 5 instead.", bus, address); | 411 | usbmuxd_log(LL_NOTICE, "Could not get configuration %i descriptor for device %i-%i: %s", j, bus, address, libusb_error_name(res)); |
411 | desired_config = 5; | 412 | continue; |
412 | } | 413 | } |
413 | /* verify if the configuration 5 is actually usable */ | 414 | for(k = 0 ; k < config->bNumInterfaces ; k++) { |
414 | do { | 415 | intf = &config->interface[k].altsetting[0]; |
415 | struct libusb_config_descriptor *config; | 416 | if(intf->bInterfaceClass == INTERFACE_CLASS || |
416 | const struct libusb_interface_descriptor *intf; | 417 | intf->bInterfaceSubClass == INTERFACE_SUBCLASS || |
417 | if (libusb_get_config_descriptor_by_value(dev, 5, &config) != 0) { | 418 | intf->bInterfaceProtocol == INTERFACE_PROTOCOL) { |
418 | usbmuxd_log(LL_WARNING, "Device %d-%d: Failed to get config descriptor for configuration 5, choosing configuration 4 instead.", bus, address); | 419 | usbmuxd_log(LL_NOTICE, "Found usbmux interface for device %i-%i: %i", bus, address, intf->bInterfaceNumber); |
419 | desired_config = 4; | 420 | if(intf->bNumEndpoints != 2) { |
420 | break; | 421 | usbmuxd_log(LL_WARNING, "Endpoint count mismatch for interface %i of device %i-%i", intf->bInterfaceNumber, bus, address); |
421 | } | 422 | continue; |
422 | // In Valeria mode, there are 3 interfaces and usbmuxd is at 2 | 423 | } |
423 | // In CDC NCM mode, there are 4 interfaces and usbmuxd is at 1 | 424 | if((intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT && |
424 | // Otherwize, 0 is expected to be of a different class. | 425 | (intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) { |
425 | int usbmux_intf_index = config->bNumInterfaces == 3 ? 2 : config->bNumInterfaces == 4 ? 1 : 0; | 426 | usbdev->interface = intf->bInterfaceNumber; |
426 | intf = &config->interface[usbmux_intf_index].altsetting[0]; | 427 | usbdev->ep_out = intf->endpoint[0].bEndpointAddress; |
427 | if(intf->bInterfaceClass != INTERFACE_CLASS || | 428 | usbdev->ep_in = intf->endpoint[1].bEndpointAddress; |
428 | intf->bInterfaceSubClass != INTERFACE_SUBCLASS || | 429 | usbmuxd_log(LL_INFO, "Found interface %i with endpoints %02x/%02x for device %i-%i", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address); |
429 | intf->bInterfaceProtocol != INTERFACE_PROTOCOL) { | 430 | found = 1; |
430 | usbmuxd_log(LL_WARNING, "Device %d-%d: can't find usbmux interface in configuration 5, choosing configuration 4 instead.", bus, address); | 431 | break; |
431 | desired_config = 4; | 432 | } else if((intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT && |
433 | (intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) { | ||
434 | usbdev->interface = intf->bInterfaceNumber; | ||
435 | usbdev->ep_out = intf->endpoint[1].bEndpointAddress; | ||
436 | usbdev->ep_in = intf->endpoint[0].bEndpointAddress; | ||
437 | usbmuxd_log(LL_INFO, "Found interface %i with swapped endpoints %02x/%02x for device %i-%i", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address); | ||
438 | found = 1; | ||
439 | break; | ||
440 | } else { | ||
441 | usbmuxd_log(LL_WARNING, "Endpoint type mismatch for interface %i of device %i-%i", intf->bInterfaceNumber, bus, address); | ||
442 | } | ||
432 | } | 443 | } |
444 | } | ||
445 | if(!found) { | ||
433 | libusb_free_config_descriptor(config); | 446 | libusb_free_config_descriptor(config); |
434 | } while (0); | 447 | continue; |
435 | } | 448 | } |
436 | int current_config = 0; | 449 | // If set configuration is required, try to first detach all kernel drivers |
437 | if((res = libusb_get_configuration(handle, ¤t_config)) != 0) { | ||
438 | usbmuxd_log(LL_WARNING, "Could not get configuration for device %d-%d: %s", bus, address, libusb_error_name(res)); | ||
439 | usbdev->alive = 0; | ||
440 | return; | ||
441 | } | ||
442 | if (current_config != desired_config) { | ||
443 | struct libusb_config_descriptor *config; | ||
444 | if (current_config == 0) { | 450 | if (current_config == 0) { |
445 | usbmuxd_log(LL_DEBUG, "Device %d-%d is unconfigured", bus, address); | 451 | usbmuxd_log(LL_DEBUG, "Device %d-%d is unconfigured", bus, address); |
446 | } else if ((res = libusb_get_active_config_descriptor(dev, &config)) != 0) { | 452 | } |
447 | usbmuxd_log(LL_NOTICE, "Could not get old configuration descriptor for device %d-%d: %s", bus, address, libusb_error_name(res)); | 453 | if(current_config == 0 || config->bConfigurationValue != current_config) { |
448 | } else { | 454 | usbmuxd_log(LL_NOTICE, "Changing configuration of device %i-%i: %i -> %i", bus, address, config->bConfigurationValue, current_config); |
449 | for(j=0; j<config->bNumInterfaces; j++) { | 455 | for(k=0 ; k < config->bNumInterfaces ; k++) { |
450 | const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0]; | 456 | const struct libusb_interface_descriptor *intf1 = &config->interface[k].altsetting[0]; |
451 | if((res = libusb_kernel_driver_active(handle, intf->bInterfaceNumber)) < 0) { | 457 | if((res = libusb_kernel_driver_active(handle, intf1->bInterfaceNumber)) < 0) { |
452 | usbmuxd_log(LL_NOTICE, "Could not check kernel ownership of interface %d for device %d-%d: %s", intf->bInterfaceNumber, bus, address, libusb_error_name(res)); | 458 | usbmuxd_log(LL_NOTICE, "Could not check kernel ownership of interface %d for device %d-%d: %s", intf1->bInterfaceNumber, bus, address, libusb_error_name(res)); |
453 | continue; | 459 | continue; |
454 | } | 460 | } |
455 | if(res == 1) { | 461 | if(res == 1) { |
456 | usbmuxd_log(LL_INFO, "Detaching kernel driver for device %d-%d, interface %d", bus, address, intf->bInterfaceNumber); | 462 | usbmuxd_log(LL_INFO, "Detaching kernel driver for device %d-%d, interface %d", bus, address, intf1->bInterfaceNumber); |
457 | if((res = libusb_detach_kernel_driver(handle, intf->bInterfaceNumber)) < 0) { | 463 | if((res = libusb_detach_kernel_driver(handle, intf1->bInterfaceNumber)) < 0) { |
458 | usbmuxd_log(LL_WARNING, "Could not detach kernel driver, configuration change will probably fail! %s", libusb_error_name(res)); | 464 | usbmuxd_log(LL_WARNING, "Could not detach kernel driver, configuration change will probably fail! %s", libusb_error_name(res)); |
459 | continue; | 465 | continue; |
460 | } | 466 | } |
461 | } | 467 | } |
462 | } | 468 | } |
463 | libusb_free_config_descriptor(config); | 469 | if((res = libusb_set_configuration(handle, j)) != 0) { |
464 | } | 470 | usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %s", j, bus, address, libusb_error_name(res)); |
465 | 471 | libusb_free_config_descriptor(config); | |
466 | usbmuxd_log(LL_INFO, "Setting configuration for device %d-%d, from %d to %d", bus, address, current_config, desired_config); | 472 | continue; |
467 | if((res = libusb_set_configuration(handle, desired_config)) != 0) { | 473 | } |
468 | usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %s", desired_config, bus, address, libusb_error_name(res)); | ||
469 | usbdev->alive = 0; | ||
470 | return; | ||
471 | } | 474 | } |
475 | |||
476 | libusb_free_config_descriptor(config); | ||
477 | break; | ||
472 | } | 478 | } |
473 | 479 | ||
474 | struct libusb_config_descriptor *config; | 480 | if(!found) { |
475 | if((res = libusb_get_active_config_descriptor(dev, &config)) != 0) { | 481 | usbmuxd_log(LL_WARNING, "Could not find a suitable USB interface for device %i-%i", bus, address); |
476 | usbmuxd_log(LL_WARNING, "Could not get configuration descriptor for device %d-%d: %s", bus, address, libusb_error_name(res)); | 482 | return -1; |
477 | usbdev->alive = 0; | ||
478 | return; | ||
479 | } | 483 | } |
480 | 484 | ||
481 | for(j=0; j<config->bNumInterfaces; j++) { | 485 | return 0; |
482 | const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0]; | 486 | } |
483 | if(intf->bInterfaceClass != INTERFACE_CLASS || | 487 | |
484 | intf->bInterfaceSubClass != INTERFACE_SUBCLASS || | 488 | static void device_complete_initialization(struct mode_context *context, struct libusb_device_handle *handle) |
485 | intf->bInterfaceProtocol != INTERFACE_PROTOCOL) | 489 | { |
486 | continue; | 490 | struct usb_device *usbdev = find_device(context->bus, context->address); |
487 | if(intf->bNumEndpoints != 2) { | 491 | if(!usbdev) { |
488 | usbmuxd_log(LL_WARNING, "Endpoint count mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address); | 492 | usbmuxd_log(LL_ERROR, "Device %d-%d is missing from device list, aborting initialization", context->bus, context->address); |
489 | continue; | 493 | return; |
490 | } | ||
491 | if((intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT && | ||
492 | (intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) { | ||
493 | usbdev->interface = intf->bInterfaceNumber; | ||
494 | usbdev->ep_out = intf->endpoint[0].bEndpointAddress; | ||
495 | usbdev->ep_in = intf->endpoint[1].bEndpointAddress; | ||
496 | usbmuxd_log(LL_INFO, "Found interface %d with endpoints %02x/%02x for device %d-%d", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address); | ||
497 | break; | ||
498 | } else if((intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT && | ||
499 | (intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) { | ||
500 | usbdev->interface = intf->bInterfaceNumber; | ||
501 | usbdev->ep_out = intf->endpoint[1].bEndpointAddress; | ||
502 | usbdev->ep_in = intf->endpoint[0].bEndpointAddress; | ||
503 | usbmuxd_log(LL_INFO, "Found interface %d with swapped endpoints %02x/%02x for device %d-%d", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address); | ||
504 | break; | ||
505 | } else { | ||
506 | usbmuxd_log(LL_WARNING, "Endpoint type mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address); | ||
507 | } | ||
508 | } | 494 | } |
495 | struct libusb_device *dev = context->dev; | ||
496 | struct libusb_device_descriptor devdesc = usbdev->devdesc; | ||
497 | int bus = context->bus; | ||
498 | int address = context->address; | ||
499 | int res; | ||
500 | struct libusb_transfer *transfer; | ||
509 | 501 | ||
510 | if(j == config->bNumInterfaces) { | 502 | if((res = set_valid_configuration(dev, usbdev, handle)) != 0) { |
511 | usbmuxd_log(LL_WARNING, "Could not find a suitable USB interface for device %d-%d", bus, address); | ||
512 | libusb_free_config_descriptor(config); | ||
513 | usbdev->alive = 0; | 503 | usbdev->alive = 0; |
514 | return; | 504 | return; |
515 | } | 505 | } |
516 | 506 | ||
517 | libusb_free_config_descriptor(config); | ||
518 | |||
519 | if((res = libusb_claim_interface(handle, usbdev->interface)) != 0) { | 507 | if((res = libusb_claim_interface(handle, usbdev->interface)) != 0) { |
520 | usbmuxd_log(LL_WARNING, "Could not claim interface %d for device %d-%d: %s", usbdev->interface, bus, address, libusb_error_name(res)); | 508 | usbmuxd_log(LL_WARNING, "Could not claim interface %d for device %d-%d: %s", usbdev->interface, bus, address, libusb_error_name(res)); |
521 | usbdev->alive = 0; | 509 | usbdev->alive = 0; |