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; |
