summaryrefslogtreecommitdiffstats
path: root/src/usb.c
diff options
context:
space:
mode:
authorGravatar Eliyahu Stern2022-12-22 21:24:17 +0200
committerGravatar Eliyahu Stern2022-12-22 21:24:17 +0200
commit939595af0e38ae6cd8af698d29153160300c97bd (patch)
tree7d527275acf618a455a4453edf3e75696e2b9d3b /src/usb.c
parent9bc87cd244129f1e266168e5b941b6c4b412c2a3 (diff)
downloadusbmuxd-939595af0e38ae6cd8af698d29153160300c97bd.tar.gz
usbmuxd-939595af0e38ae6cd8af698d29153160300c97bd.tar.bz2
Factor out device_complete_initialization and call it from get_mode_cb.
Handle some memory issues.
Diffstat (limited to 'src/usb.c')
-rw-r--r--src/usb.c268
1 files changed, 141 insertions, 127 deletions
diff --git a/src/usb.c b/src/usb.c
index 3e2d3b1..f380b60 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -65,12 +65,12 @@ struct usb_device {
65 struct libusb_device_descriptor devdesc; 65 struct libusb_device_descriptor devdesc;
66}; 66};
67 67
68struct mode_user_data { 68struct mode_context {
69 struct libusb_device* dev;
70 struct libusb_device_descriptor devdesc;
69 uint8_t bus, address; 71 uint8_t bus, address;
70 uint8_t bRequest; 72 uint8_t bRequest;
71 uint16_t wValue; 73 uint16_t wValue, wIndex, wLength;
72 uint16_t wIndex;
73 uint16_t wLength;
74 unsigned int timeout; 74 unsigned int timeout;
75}; 75};
76 76
@@ -366,140 +366,31 @@ static void get_langid_callback(struct libusb_transfer *transfer)
366 } 366 }
367} 367}
368 368
369static int submit_vendor_specific(struct libusb_device_handle *handle, struct mode_user_data *user_data, libusb_transfer_cb_fn callback) 369static int submit_vendor_specific(struct libusb_device_handle *handle, struct mode_context *context, libusb_transfer_cb_fn callback)
370{ 370{
371 struct libusb_transfer* ctrl_transfer = libusb_alloc_transfer(0); 371 struct libusb_transfer* ctrl_transfer = libusb_alloc_transfer(0);
372 unsigned char* buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE); 372 int ret = 0;
373 unsigned char* buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE + context->wLength);
373 uint8_t bRequestType = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE; 374 uint8_t bRequestType = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE;
374 libusb_fill_control_setup(buffer, bRequestType, user_data->bRequest, user_data->wValue, user_data->wIndex, user_data->wLength); 375 libusb_fill_control_setup(buffer, bRequestType, context->bRequest, context->wValue, context->wIndex, context->wLength);
375 376
376 ctrl_transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; 377 ctrl_transfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER | LIBUSB_TRANSFER_FREE_TRANSFER;
377 libusb_fill_control_transfer(ctrl_transfer, handle, buffer, callback, user_data, user_data->timeout); 378 libusb_fill_control_transfer(ctrl_transfer, handle, buffer, callback, context, context->timeout);
378 379
379 return libusb_submit_transfer(ctrl_transfer); 380 ret = libusb_submit_transfer(ctrl_transfer);
381 return ret;
380} 382}
381 383
382static void switch_mode_cb(struct libusb_transfer* transfer) 384static int device_complete_initialization(struct mode_context *context, struct libusb_device_handle *handle)
383{
384 struct mode_user_data* user_data = transfer->user_data;
385
386 if(transfer->status != LIBUSB_TRANSFER_COMPLETED) {
387 usbmuxd_log(LL_ERROR, "Failed to request mode switch for device %i-%i (%i)", user_data->bus, user_data->address, transfer->status);
388 free(transfer->user_data);
389 return;
390 }
391
392 unsigned char *data = libusb_control_transfer_get_data(transfer);
393
394 usbmuxd_log(LL_INFO, "Received response %i for switch mode %i for device %i-%i", data[0], user_data->wIndex, user_data->bus, user_data->address);
395 free(transfer->user_data);
396}
397
398static void get_mode_cb(struct libusb_transfer* transfer)
399{
400 struct mode_user_data* user_data = transfer->user_data;
401 int res;
402
403 if(transfer->status != LIBUSB_TRANSFER_COMPLETED) {
404 usbmuxd_log(LL_ERROR, "Failed to request get mode for device %i-%i (%i)", user_data->bus, user_data->address, transfer->status);
405 free(transfer->user_data);
406 return;
407 }
408
409 unsigned char *data = libusb_control_transfer_get_data(transfer);
410
411 char* desired_mode = getenv(ENV_DEVICE_MODE);
412 if(!desired_mode) {
413 user_data->wIndex = 0x1;
414 }
415 else if(!strncmp(desired_mode, "2", 1)) {
416 user_data->wIndex = 0x2;
417 }
418 else if(!strncmp(desired_mode, "3", 1)) {
419 user_data->wIndex = 0x3;
420 }
421 // Response is 3:3:3 for initial mode, 5:3:3 otherwise.
422 // In later commit, should infer the mode from available configurations and interfaces.
423 usbmuxd_log(LL_INFO, "Received response %i:%i:%i for get_mode request for device %i-%i", data[0], data[1], data[2], user_data->bus, user_data->address);
424 if(user_data->wIndex > 1 && data[0] == 3 && data[1] == 3 && data[2] == 3) {
425 // 3:3:3 means the initial mode
426 usbmuxd_log(LL_WARNING, "Switching device %i-%i mode to %i", user_data->bus, user_data->address, user_data->wIndex);
427
428 user_data->bRequest = APPLE_VEND_SPECIFIC_SET_MODE;
429 user_data->wValue = 0;
430 user_data->wLength = 1;
431
432 if((res = submit_vendor_specific(transfer->dev_handle, user_data, switch_mode_cb)) != 0) {
433 usbmuxd_log(LL_WARNING, "Could not request to switch mode %i for device %i-%i (%i)", user_data->wIndex, user_data->bus, user_data->address, res);
434 }
435 }
436 else {
437 // in other modes, usually 5:3:3
438 usbmuxd_log(LL_WARNING, "Skipping switch device %i-%i mode", user_data->bus, user_data->address);
439 free(transfer->user_data);
440 }
441}
442
443static int usb_device_add(libusb_device* dev)
444{ 385{
386 struct libusb_device *dev = context->dev;
387 struct libusb_device_descriptor devdesc = context->devdesc;
388 int bus = context->bus;
389 int address = context->address;
390 int desired_config = devdesc.bNumConfigurations;
445 int j, res; 391 int j, res;
446 // the following are non-blocking operations on the device list
447 uint8_t bus = libusb_get_bus_number(dev);
448 uint8_t address = libusb_get_device_address(dev);
449 struct libusb_device_descriptor devdesc;
450 struct libusb_transfer *transfer; 392 struct libusb_transfer *transfer;
451 int found = 0;
452 FOREACH(struct usb_device *usbdev, &device_list) {
453 if(usbdev->bus == bus && usbdev->address == address) {
454 usbdev->alive = 1;
455 found = 1;
456 break;
457 }
458 } ENDFOREACH
459 if(found)
460 return 0; //device already found
461
462 if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) {
463 usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %s", bus, address, libusb_error_name(res));
464 return -1;
465 }
466 if(devdesc.idVendor != VID_APPLE)
467 return -1;
468 if((devdesc.idProduct != PID_APPLE_T2_COPROCESSOR) &&
469 ((devdesc.idProduct < PID_APPLE_SILICON_RESTORE_LOW) ||
470 (devdesc.idProduct > PID_APPLE_SILICON_RESTORE_MAX)) &&
471 ((devdesc.idProduct < PID_RANGE_LOW) ||
472 (devdesc.idProduct > PID_RANGE_MAX)))
473 return -1;
474 libusb_device_handle *handle;
475 usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address);
476 // No blocking operation can follow: it may be run in the libusb hotplug callback and libusb will refuse any
477 // blocking call
478 if((res = libusb_open(dev, &handle)) != 0) {
479 usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %s", bus, address, libusb_error_name(res));
480 return -1;
481 }
482 393
483 // On top of configurations, Apple have multiple "modes" for devices, namely:
484 // 1: An "initial" mode with 4 configurations
485 // 2: "Valeria" mode, where configuration 5 is included with interface for H.265 video capture (activated when recording screen with QuickTime in macOS)
486 // 3: "CDC NCM" mode, where configuration 5 is included with interface for Ethernet/USB (activated using internet-sharing feature in macOS)
487 // Request current mode asynchroniously, so it can be changed in callback if needed
488 usbmuxd_log(LL_INFO, "Requesting current mode from device %i-%i", bus, address);
489 struct mode_user_data* user_data = malloc(sizeof(struct mode_user_data));
490 user_data->bus = bus;
491 user_data->address = address;
492 user_data->bRequest = APPLE_VEND_SPECIFIC_GET_MODE;
493 user_data->wValue = 0;
494 user_data->wIndex = 0;
495 user_data->wLength = 4;
496 user_data->timeout = 1000;
497
498 if(submit_vendor_specific(handle, user_data, get_mode_cb) != 0) {
499 usbmuxd_log(LL_WARNING, "Could not request current mode from device %d-%d", bus, address);
500 }
501 // Potentially, the rest of this function can be factored out and called from get_mode_callback/switch_mode_callback (where desired mode is known)
502 int desired_config = devdesc.bNumConfigurations;
503 if(desired_config > 4) { 394 if(desired_config > 4) {
504 if(desired_config > 5) { 395 if(desired_config > 5) {
505 usbmuxd_log(LL_ERROR, "Device %d-%d has more than 5 configurations, but usbmuxd doesn't support that. Choosing configuration 5 instead.", bus, address); 396 usbmuxd_log(LL_ERROR, "Device %d-%d has more than 5 configurations, but usbmuxd doesn't support that. Choosing configuration 5 instead.", bus, address);
@@ -700,6 +591,129 @@ static int usb_device_add(libusb_device* dev)
700 return 0; 591 return 0;
701} 592}
702 593
594static void switch_mode_cb(struct libusb_transfer* transfer)
595{
596 struct mode_context* context = transfer->user_data;
597
598 if(transfer->status != LIBUSB_TRANSFER_COMPLETED) {
599 usbmuxd_log(LL_ERROR, "Failed to request mode switch for device %i-%i (%i)", context->bus, context->address, transfer->status);
600 }
601 else {
602 unsigned char *data = libusb_control_transfer_get_data(transfer);
603 usbmuxd_log(LL_INFO, "Received response %i for switch mode %i for device %i-%i", data[0], context->wIndex, context->bus, context->address);
604 }
605 free(transfer->user_data);
606}
607
608static void get_mode_cb(struct libusb_transfer* transfer)
609{
610 struct mode_context* context = transfer->user_data;
611 int res;
612
613 if(transfer->status != LIBUSB_TRANSFER_COMPLETED) {
614 usbmuxd_log(LL_ERROR, "Failed to request get mode for device %i-%i (%i)", context->bus, context->address, transfer->status);
615 free(context);
616 return;
617 }
618
619 unsigned char *data = libusb_control_transfer_get_data(transfer);
620
621 char* desired_mode = getenv(ENV_DEVICE_MODE);
622 if(!desired_mode) {
623 context->wIndex = 0x1;
624 }
625 else if(!strncmp(desired_mode, "2", 1)) {
626 context->wIndex = 0x2;
627 }
628 else if(!strncmp(desired_mode, "3", 1)) {
629 context->wIndex = 0x3;
630 }
631 // Response is 3:3:3 for initial mode, 5:3:3 otherwise.
632 // In later commit, should infer the mode from available configurations and interfaces.
633 usbmuxd_log(LL_INFO, "Received response %i:%i:%i for get_mode request for device %i-%i", data[0], data[1], data[2], context->bus, context->address);
634 if(context->wIndex > 1 && data[0] == 3 && data[1] == 3 && data[2] == 3) {
635 // 3:3:3 means the initial mode
636 usbmuxd_log(LL_WARNING, "Switching device %i-%i mode to %i", context->bus, context->address, context->wIndex);
637
638 context->bRequest = APPLE_VEND_SPECIFIC_SET_MODE;
639 context->wValue = 0;
640 context->wLength = 1;
641
642 if((res = submit_vendor_specific(transfer->dev_handle, context, switch_mode_cb)) != 0) {
643 usbmuxd_log(LL_WARNING, "Could not request to switch mode %i for device %i-%i (%i)", context->wIndex, context->bus, context->address, res);
644 }
645 }
646 else {
647 // in other modes, usually 5:3:3
648 usbmuxd_log(LL_WARNING, "Skipping switch device %i-%i mode", context->bus, context->address);
649 device_complete_initialization(context, transfer->dev_handle);
650 free(context);
651 }
652}
653
654static int usb_device_add(libusb_device* dev)
655{
656 int res;
657 // the following are non-blocking operations on the device list
658 uint8_t bus = libusb_get_bus_number(dev);
659 uint8_t address = libusb_get_device_address(dev);
660 struct libusb_device_descriptor devdesc;
661 int found = 0;
662 FOREACH(struct usb_device *usbdev, &device_list) {
663 if(usbdev->bus == bus && usbdev->address == address) {
664 usbdev->alive = 1;
665 found = 1;
666 break;
667 }
668 } ENDFOREACH
669 if(found)
670 return 0; //device already found
671
672 if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) {
673 usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %s", bus, address, libusb_error_name(res));
674 return -1;
675 }
676 if(devdesc.idVendor != VID_APPLE)
677 return -1;
678 if((devdesc.idProduct != PID_APPLE_T2_COPROCESSOR) &&
679 ((devdesc.idProduct < PID_APPLE_SILICON_RESTORE_LOW) ||
680 (devdesc.idProduct > PID_APPLE_SILICON_RESTORE_MAX)) &&
681 ((devdesc.idProduct < PID_RANGE_LOW) ||
682 (devdesc.idProduct > PID_RANGE_MAX)))
683 return -1;
684 libusb_device_handle *handle;
685 usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address);
686 // No blocking operation can follow: it may be run in the libusb hotplug callback and libusb will refuse any
687 // blocking call
688 if((res = libusb_open(dev, &handle)) != 0) {
689 usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %s", bus, address, libusb_error_name(res));
690 return -1;
691 }
692
693 // On top of configurations, Apple have multiple "modes" for devices, namely:
694 // 1: An "initial" mode with 4 configurations
695 // 2: "Valeria" mode, where configuration 5 is included with interface for H.265 video capture (activated when recording screen with QuickTime in macOS)
696 // 3: "CDC NCM" mode, where configuration 5 is included with interface for Ethernet/USB (activated using internet-sharing feature in macOS)
697 // Request current mode asynchroniously, so it can be changed in callback if needed
698 usbmuxd_log(LL_INFO, "Requesting current mode from device %i-%i", bus, address);
699 struct mode_context* context = malloc(sizeof(struct mode_context));
700 context->dev = dev;
701 context->devdesc = devdesc;
702 context->bus = bus;
703 context->address = address;
704 context->bRequest = APPLE_VEND_SPECIFIC_GET_MODE;
705 context->wValue = 0;
706 context->wIndex = 0;
707 context->wLength = 4;
708 context->timeout = 1000;
709
710 if(submit_vendor_specific(handle, context, get_mode_cb) != 0) {
711 usbmuxd_log(LL_WARNING, "Could not request current mode from device %d-%d", bus, address);
712 return -1;
713 }
714 return 0;
715}
716
703int usb_discover(void) 717int usb_discover(void)
704{ 718{
705 int cnt, i; 719 int cnt, i;