diff options
| author | 2014-11-11 14:47:22 +0100 | |
|---|---|---|
| committer | 2014-12-02 19:16:43 +0100 | |
| commit | b752fbc1dd92238a34c888fbaef921aa802c4a82 (patch) | |
| tree | 36734c11879da01995b037cf104cbca4ef0c4b79 | |
| parent | ab51bbbe6d78678db1bdd04be1eeec6bb1d59c34 (diff) | |
| download | usbmuxd-b752fbc1dd92238a34c888fbaef921aa802c4a82.tar.gz usbmuxd-b752fbc1dd92238a34c888fbaef921aa802c4a82.tar.bz2 | |
usb: Implement device discovery using libusb hotplug events
| -rw-r--r-- | src/usb.c | 470 |
1 files changed, 268 insertions, 202 deletions
| @@ -36,6 +36,10 @@ | |||
| 36 | #include "device.h" | 36 | #include "device.h" |
| 37 | #include "utils.h" | 37 | #include "utils.h" |
| 38 | 38 | ||
| 39 | #if (defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000102)) || (defined(LIBUSBX_API_VERSION) && (LIBUSBX_API_VERSION >= 0x01000102)) | ||
| 40 | #define HAVE_LIBUSB_HOTPLUG_API 1 | ||
| 41 | #endif | ||
| 42 | |||
| 39 | // interval for device connection/disconnection polling, in milliseconds | 43 | // interval for device connection/disconnection polling, in milliseconds |
| 40 | // we need this because there is currently no asynchronous device discovery mechanism in libusb | 44 | // we need this because there is currently no asynchronous device discovery mechanism in libusb |
| 41 | #define DEVICE_POLL_TIME 1000 | 45 | #define DEVICE_POLL_TIME 1000 |
| @@ -65,6 +69,7 @@ static struct timeval next_dev_poll_time; | |||
| 65 | 69 | ||
| 66 | static int devlist_failures; | 70 | static int devlist_failures; |
| 67 | static int device_polling; | 71 | static int device_polling; |
| 72 | static int device_hotplug = 1; | ||
| 68 | 73 | ||
| 69 | static void usb_disconnect(struct usb_device *dev) | 74 | static void usb_disconnect(struct usb_device *dev) |
| 70 | { | 75 | { |
| @@ -253,9 +258,217 @@ static int start_rx_loop(struct usb_device *dev) | |||
| 253 | return 0; | 258 | return 0; |
| 254 | } | 259 | } |
| 255 | 260 | ||
| 261 | static int usb_device_add(libusb_device* dev) | ||
| 262 | { | ||
| 263 | int j, res; | ||
| 264 | // the following are non-blocking operations on the device list | ||
| 265 | uint8_t bus = libusb_get_bus_number(dev); | ||
| 266 | uint8_t address = libusb_get_device_address(dev); | ||
| 267 | struct libusb_device_descriptor devdesc; | ||
| 268 | int found = 0; | ||
| 269 | FOREACH(struct usb_device *usbdev, &device_list) { | ||
| 270 | if(usbdev->bus == bus && usbdev->address == address) { | ||
| 271 | usbdev->alive = 1; | ||
| 272 | found = 1; | ||
| 273 | break; | ||
| 274 | } | ||
| 275 | } ENDFOREACH | ||
| 276 | if(found) | ||
| 277 | return 0; //device already found | ||
| 278 | |||
| 279 | if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) { | ||
| 280 | usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %d", bus, address, res); | ||
| 281 | return -1; | ||
| 282 | } | ||
| 283 | if(devdesc.idVendor != VID_APPLE) | ||
| 284 | return -1; | ||
| 285 | if((devdesc.idProduct < PID_RANGE_LOW) || | ||
| 286 | (devdesc.idProduct > PID_RANGE_MAX)) | ||
| 287 | return -1; | ||
| 288 | libusb_device_handle *handle; | ||
| 289 | usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address); | ||
| 290 | // potentially blocking operations follow; they will only run when new devices are detected, which is acceptable | ||
| 291 | if((res = libusb_open(dev, &handle)) != 0) { | ||
| 292 | usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %d", bus, address, res); | ||
| 293 | return -1; | ||
| 294 | } | ||
| 295 | |||
| 296 | int current_config = 0; | ||
| 297 | if((res = libusb_get_configuration(handle, ¤t_config)) != 0) { | ||
| 298 | usbmuxd_log(LL_WARNING, "Could not get configuration for device %d-%d: %d", bus, address, res); | ||
| 299 | libusb_close(handle); | ||
| 300 | return -1; | ||
| 301 | } | ||
| 302 | if (current_config != devdesc.bNumConfigurations) { | ||
| 303 | struct libusb_config_descriptor *config; | ||
| 304 | if((res = libusb_get_active_config_descriptor(dev, &config)) != 0) { | ||
| 305 | usbmuxd_log(LL_NOTICE, "Could not get old configuration descriptor for device %d-%d: %d", bus, address, res); | ||
| 306 | } else { | ||
| 307 | for(j=0; j<config->bNumInterfaces; j++) { | ||
| 308 | const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0]; | ||
| 309 | if((res = libusb_kernel_driver_active(handle, intf->bInterfaceNumber)) < 0) { | ||
| 310 | usbmuxd_log(LL_NOTICE, "Could not check kernel ownership of interface %d for device %d-%d: %d", intf->bInterfaceNumber, bus, address, res); | ||
| 311 | continue; | ||
| 312 | } | ||
| 313 | if(res == 1) { | ||
| 314 | usbmuxd_log(LL_INFO, "Detaching kernel driver for device %d-%d, interface %d", bus, address, intf->bInterfaceNumber); | ||
| 315 | if((res = libusb_detach_kernel_driver(handle, intf->bInterfaceNumber)) < 0) { | ||
| 316 | usbmuxd_log(LL_WARNING, "Could not detach kernel driver (%d), configuration change will probably fail!", res); | ||
| 317 | continue; | ||
| 318 | } | ||
| 319 | } | ||
| 320 | } | ||
| 321 | libusb_free_config_descriptor(config); | ||
| 322 | } | ||
| 323 | |||
| 324 | usbmuxd_log(LL_INFO, "Setting configuration for device %d-%d, from %d to %d", bus, address, current_config, devdesc.bNumConfigurations); | ||
| 325 | if((res = libusb_set_configuration(handle, devdesc.bNumConfigurations)) != 0) { | ||
| 326 | usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %d", devdesc.bNumConfigurations, bus, address, res); | ||
| 327 | libusb_close(handle); | ||
| 328 | return -1; | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | struct libusb_config_descriptor *config; | ||
| 333 | if((res = libusb_get_active_config_descriptor(dev, &config)) != 0) { | ||
| 334 | usbmuxd_log(LL_WARNING, "Could not get configuration descriptor for device %d-%d: %d", bus, address, res); | ||
| 335 | libusb_close(handle); | ||
| 336 | return -1; | ||
| 337 | } | ||
| 338 | |||
| 339 | struct usb_device *usbdev; | ||
| 340 | usbdev = malloc(sizeof(struct usb_device)); | ||
| 341 | memset(usbdev, 0, sizeof(*usbdev)); | ||
| 342 | |||
| 343 | for(j=0; j<config->bNumInterfaces; j++) { | ||
| 344 | const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0]; | ||
| 345 | if(intf->bInterfaceClass != INTERFACE_CLASS || | ||
| 346 | intf->bInterfaceSubClass != INTERFACE_SUBCLASS || | ||
| 347 | intf->bInterfaceProtocol != INTERFACE_PROTOCOL) | ||
| 348 | continue; | ||
| 349 | if(intf->bNumEndpoints != 2) { | ||
| 350 | usbmuxd_log(LL_WARNING, "Endpoint count mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address); | ||
| 351 | continue; | ||
| 352 | } | ||
| 353 | if((intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT && | ||
| 354 | (intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) { | ||
| 355 | usbdev->interface = intf->bInterfaceNumber; | ||
| 356 | usbdev->ep_out = intf->endpoint[0].bEndpointAddress; | ||
| 357 | usbdev->ep_in = intf->endpoint[1].bEndpointAddress; | ||
| 358 | 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); | ||
| 359 | break; | ||
| 360 | } else if((intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT && | ||
| 361 | (intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) { | ||
| 362 | usbdev->interface = intf->bInterfaceNumber; | ||
| 363 | usbdev->ep_out = intf->endpoint[1].bEndpointAddress; | ||
| 364 | usbdev->ep_in = intf->endpoint[0].bEndpointAddress; | ||
| 365 | 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); | ||
| 366 | break; | ||
| 367 | } else { | ||
| 368 | usbmuxd_log(LL_WARNING, "Endpoint type mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address); | ||
| 369 | } | ||
| 370 | } | ||
| 371 | |||
| 372 | if(j == config->bNumInterfaces) { | ||
| 373 | usbmuxd_log(LL_WARNING, "Could not find a suitable USB interface for device %d-%d", bus, address); | ||
| 374 | libusb_free_config_descriptor(config); | ||
| 375 | libusb_close(handle); | ||
| 376 | free(usbdev); | ||
| 377 | return -1; | ||
| 378 | } | ||
| 379 | |||
| 380 | libusb_free_config_descriptor(config); | ||
| 381 | |||
| 382 | if((res = libusb_claim_interface(handle, usbdev->interface)) != 0) { | ||
| 383 | usbmuxd_log(LL_WARNING, "Could not claim interface %d for device %d-%d: %d", usbdev->interface, bus, address, res); | ||
| 384 | libusb_close(handle); | ||
| 385 | free(usbdev); | ||
| 386 | return -1; | ||
| 387 | } | ||
| 388 | |||
| 389 | if((res = libusb_get_string_descriptor_ascii(handle, devdesc.iSerialNumber, (uint8_t *)usbdev->serial, 256)) <= 0) { | ||
| 390 | usbmuxd_log(LL_WARNING, "Could not get serial number for device %d-%d: %d", bus, address, res); | ||
| 391 | libusb_release_interface(handle, usbdev->interface); | ||
| 392 | libusb_close(handle); | ||
| 393 | free(usbdev); | ||
| 394 | return -1; | ||
| 395 | } | ||
| 396 | usbdev->serial[res] = 0; | ||
| 397 | usbdev->bus = bus; | ||
| 398 | usbdev->address = address; | ||
| 399 | usbdev->vid = devdesc.idVendor; | ||
| 400 | usbdev->pid = devdesc.idProduct; | ||
| 401 | usbdev->speed = 480000000; | ||
| 402 | usbdev->dev = handle; | ||
| 403 | usbdev->alive = 1; | ||
| 404 | usbdev->wMaxPacketSize = libusb_get_max_packet_size(dev, usbdev->ep_out); | ||
| 405 | if (usbdev->wMaxPacketSize <= 0) { | ||
| 406 | usbmuxd_log(LL_ERROR, "Could not determine wMaxPacketSize for device %d-%d, setting to 64", usbdev->bus, usbdev->address); | ||
| 407 | usbdev->wMaxPacketSize = 64; | ||
| 408 | } else { | ||
| 409 | usbmuxd_log(LL_INFO, "Using wMaxPacketSize=%d for device %d-%d", usbdev->wMaxPacketSize, usbdev->bus, usbdev->address); | ||
| 410 | } | ||
| 411 | |||
| 412 | switch (libusb_get_device_speed(dev)) { | ||
| 413 | case LIBUSB_SPEED_LOW: | ||
| 414 | usbdev->speed = 1500000; | ||
| 415 | break; | ||
| 416 | case LIBUSB_SPEED_FULL: | ||
| 417 | usbdev->speed = 12000000; | ||
| 418 | break; | ||
| 419 | case LIBUSB_SPEED_SUPER: | ||
| 420 | usbdev->speed = 5000000000; | ||
| 421 | break; | ||
| 422 | case LIBUSB_SPEED_HIGH: | ||
| 423 | case LIBUSB_SPEED_UNKNOWN: | ||
| 424 | default: | ||
| 425 | usbdev->speed = 480000000; | ||
| 426 | break; | ||
| 427 | } | ||
| 428 | |||
| 429 | usbmuxd_log(LL_INFO, "USB Speed is %g MBit/s for device %d-%d", (double)(usbdev->speed / 1000000.0), usbdev->bus, usbdev->address); | ||
| 430 | |||
| 431 | collection_init(&usbdev->tx_xfers); | ||
| 432 | collection_init(&usbdev->rx_xfers); | ||
| 433 | |||
| 434 | collection_add(&device_list, usbdev); | ||
| 435 | |||
| 436 | if(device_add(usbdev) < 0) { | ||
| 437 | usb_disconnect(usbdev); | ||
| 438 | return -1; | ||
| 439 | } | ||
| 440 | |||
| 441 | // Spin up NUM_RX_LOOPS parallel usb data retrieval loops | ||
| 442 | // Old usbmuxds used only 1 rx loop, but that leaves the | ||
| 443 | // USB port sleeping most of the time | ||
| 444 | int rx_loops = NUM_RX_LOOPS; | ||
| 445 | for (rx_loops = NUM_RX_LOOPS; rx_loops > 0; rx_loops--) { | ||
| 446 | if(start_rx_loop(usbdev) < 0) { | ||
| 447 | usbmuxd_log(LL_WARNING, "Failed to start RX loop number %d", NUM_RX_LOOPS - rx_loops); | ||
| 448 | } | ||
| 449 | } | ||
| 450 | |||
| 451 | // Ensure we have at least 1 RX loop going | ||
| 452 | if (rx_loops == NUM_RX_LOOPS) { | ||
| 453 | usbmuxd_log(LL_FATAL, "Failed to start any RX loop for device %d-%d", | ||
| 454 | usbdev->bus, usbdev->address); | ||
| 455 | device_remove(usbdev); | ||
| 456 | usb_disconnect(usbdev); | ||
| 457 | return -1; | ||
| 458 | } else if (rx_loops > 0) { | ||
| 459 | usbmuxd_log(LL_WARNING, "Failed to start all %d RX loops. Going on with %d loops. " | ||
| 460 | "This may have negative impact on device read speed.", | ||
| 461 | NUM_RX_LOOPS, NUM_RX_LOOPS - rx_loops); | ||
| 462 | } else { | ||
| 463 | usbmuxd_log(LL_DEBUG, "All %d RX loops started successfully", NUM_RX_LOOPS); | ||
| 464 | } | ||
| 465 | |||
| 466 | return 0; | ||
| 467 | } | ||
| 468 | |||
| 256 | int usb_discover(void) | 469 | int usb_discover(void) |
| 257 | { | 470 | { |
| 258 | int cnt, i, j, res; | 471 | int cnt, i; |
| 259 | int valid_count = 0; | 472 | int valid_count = 0; |
| 260 | libusb_device **devs; | 473 | libusb_device **devs; |
| 261 | 474 | ||
| @@ -288,209 +501,10 @@ int usb_discover(void) | |||
| 288 | // Enumerate all USB devices and mark the ones we already know | 501 | // Enumerate all USB devices and mark the ones we already know |
| 289 | // about as live, again | 502 | // about as live, again |
| 290 | for(i=0; i<cnt; i++) { | 503 | for(i=0; i<cnt; i++) { |
| 291 | // the following are non-blocking operations on the device list | ||
| 292 | libusb_device *dev = devs[i]; | 504 | libusb_device *dev = devs[i]; |
| 293 | uint8_t bus = libusb_get_bus_number(dev); | 505 | if (usb_device_add(dev) < 0) { |
| 294 | uint8_t address = libusb_get_device_address(dev); | ||
| 295 | struct libusb_device_descriptor devdesc; | ||
| 296 | int found = 0; | ||
| 297 | FOREACH(struct usb_device *usbdev, &device_list) { | ||
| 298 | if(usbdev->bus == bus && usbdev->address == address) { | ||
| 299 | valid_count++; | ||
| 300 | usbdev->alive = 1; | ||
| 301 | found = 1; | ||
| 302 | break; | ||
| 303 | } | ||
| 304 | } ENDFOREACH | ||
| 305 | if(found) | ||
| 306 | continue; //device already found | ||
| 307 | if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) { | ||
| 308 | usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %d", bus, address, res); | ||
| 309 | continue; | ||
| 310 | } | ||
| 311 | if(devdesc.idVendor != VID_APPLE) | ||
| 312 | continue; | ||
| 313 | if((devdesc.idProduct < PID_RANGE_LOW) || | ||
| 314 | (devdesc.idProduct > PID_RANGE_MAX)) | ||
| 315 | continue; | ||
| 316 | libusb_device_handle *handle; | ||
| 317 | usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address); | ||
| 318 | // potentially blocking operations follow; they will only run when new devices are detected, which is acceptable | ||
| 319 | if((res = libusb_open(dev, &handle)) != 0) { | ||
| 320 | usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %d", bus, address, res); | ||
| 321 | continue; | 506 | continue; |
| 322 | } | 507 | } |
| 323 | |||
| 324 | int current_config = 0; | ||
| 325 | if((res = libusb_get_configuration(handle, ¤t_config)) != 0) { | ||
| 326 | usbmuxd_log(LL_WARNING, "Could not get configuration for device %d-%d: %d", bus, address, res); | ||
| 327 | libusb_close(handle); | ||
| 328 | continue; | ||
| 329 | } | ||
| 330 | if (current_config != devdesc.bNumConfigurations) { | ||
| 331 | struct libusb_config_descriptor *config; | ||
| 332 | if((res = libusb_get_active_config_descriptor(dev, &config)) != 0) { | ||
| 333 | usbmuxd_log(LL_NOTICE, "Could not get old configuration descriptor for device %d-%d: %d", bus, address, res); | ||
| 334 | } else { | ||
| 335 | for(j=0; j<config->bNumInterfaces; j++) { | ||
| 336 | const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0]; | ||
| 337 | if((res = libusb_kernel_driver_active(handle, intf->bInterfaceNumber)) < 0) { | ||
| 338 | usbmuxd_log(LL_NOTICE, "Could not check kernel ownership of interface %d for device %d-%d: %d", intf->bInterfaceNumber, bus, address, res); | ||
| 339 | continue; | ||
| 340 | } | ||
| 341 | if(res == 1) { | ||
| 342 | usbmuxd_log(LL_INFO, "Detaching kernel driver for device %d-%d, interface %d", bus, address, intf->bInterfaceNumber); | ||
| 343 | if((res = libusb_detach_kernel_driver(handle, intf->bInterfaceNumber)) < 0) { | ||
| 344 | usbmuxd_log(LL_WARNING, "Could not detach kernel driver (%d), configuration change will probably fail!", res); | ||
| 345 | continue; | ||
| 346 | } | ||
| 347 | } | ||
| 348 | } | ||
| 349 | libusb_free_config_descriptor(config); | ||
| 350 | } | ||
| 351 | |||
| 352 | usbmuxd_log(LL_INFO, "Setting configuration for device %d-%d, from %d to %d", bus, address, current_config, devdesc.bNumConfigurations); | ||
| 353 | if((res = libusb_set_configuration(handle, devdesc.bNumConfigurations)) != 0) { | ||
| 354 | usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %d", devdesc.bNumConfigurations, bus, address, res); | ||
| 355 | libusb_close(handle); | ||
| 356 | continue; | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | struct libusb_config_descriptor *config; | ||
| 361 | if((res = libusb_get_active_config_descriptor(dev, &config)) != 0) { | ||
| 362 | usbmuxd_log(LL_WARNING, "Could not get configuration descriptor for device %d-%d: %d", bus, address, res); | ||
| 363 | libusb_close(handle); | ||
| 364 | continue; | ||
| 365 | } | ||
| 366 | |||
| 367 | struct usb_device *usbdev; | ||
| 368 | usbdev = malloc(sizeof(struct usb_device)); | ||
| 369 | memset(usbdev, 0, sizeof(*usbdev)); | ||
| 370 | |||
| 371 | for(j=0; j<config->bNumInterfaces; j++) { | ||
| 372 | const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0]; | ||
| 373 | if(intf->bInterfaceClass != INTERFACE_CLASS || | ||
| 374 | intf->bInterfaceSubClass != INTERFACE_SUBCLASS || | ||
| 375 | intf->bInterfaceProtocol != INTERFACE_PROTOCOL) | ||
| 376 | continue; | ||
| 377 | if(intf->bNumEndpoints != 2) { | ||
| 378 | usbmuxd_log(LL_WARNING, "Endpoint count mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address); | ||
| 379 | continue; | ||
| 380 | } | ||
| 381 | if((intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT && | ||
| 382 | (intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) { | ||
| 383 | usbdev->interface = intf->bInterfaceNumber; | ||
| 384 | usbdev->ep_out = intf->endpoint[0].bEndpointAddress; | ||
| 385 | usbdev->ep_in = intf->endpoint[1].bEndpointAddress; | ||
| 386 | 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); | ||
| 387 | break; | ||
| 388 | } else if((intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT && | ||
| 389 | (intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) { | ||
| 390 | usbdev->interface = intf->bInterfaceNumber; | ||
| 391 | usbdev->ep_out = intf->endpoint[1].bEndpointAddress; | ||
| 392 | usbdev->ep_in = intf->endpoint[0].bEndpointAddress; | ||
| 393 | 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); | ||
| 394 | break; | ||
| 395 | } else { | ||
| 396 | usbmuxd_log(LL_WARNING, "Endpoint type mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address); | ||
| 397 | } | ||
| 398 | } | ||
| 399 | |||
| 400 | if(j == config->bNumInterfaces) { | ||
| 401 | usbmuxd_log(LL_WARNING, "Could not find a suitable USB interface for device %d-%d", bus, address); | ||
| 402 | libusb_free_config_descriptor(config); | ||
| 403 | libusb_close(handle); | ||
| 404 | free(usbdev); | ||
| 405 | continue; | ||
| 406 | } | ||
| 407 | |||
| 408 | libusb_free_config_descriptor(config); | ||
| 409 | |||
| 410 | if((res = libusb_claim_interface(handle, usbdev->interface)) != 0) { | ||
| 411 | usbmuxd_log(LL_WARNING, "Could not claim interface %d for device %d-%d: %d", usbdev->interface, bus, address, res); | ||
| 412 | libusb_close(handle); | ||
| 413 | free(usbdev); | ||
| 414 | continue; | ||
| 415 | } | ||
| 416 | |||
| 417 | if((res = libusb_get_string_descriptor_ascii(handle, devdesc.iSerialNumber, (uint8_t *)usbdev->serial, 256)) <= 0) { | ||
| 418 | usbmuxd_log(LL_WARNING, "Could not get serial number for device %d-%d: %d", bus, address, res); | ||
| 419 | libusb_release_interface(handle, usbdev->interface); | ||
| 420 | libusb_close(handle); | ||
| 421 | free(usbdev); | ||
| 422 | continue; | ||
| 423 | } | ||
| 424 | usbdev->serial[res] = 0; | ||
| 425 | usbdev->bus = bus; | ||
| 426 | usbdev->address = address; | ||
| 427 | usbdev->vid = devdesc.idVendor; | ||
| 428 | usbdev->pid = devdesc.idProduct; | ||
| 429 | usbdev->speed = 480000000; | ||
| 430 | usbdev->dev = handle; | ||
| 431 | usbdev->alive = 1; | ||
| 432 | usbdev->wMaxPacketSize = libusb_get_max_packet_size(dev, usbdev->ep_out); | ||
| 433 | if (usbdev->wMaxPacketSize <= 0) { | ||
| 434 | usbmuxd_log(LL_ERROR, "Could not determine wMaxPacketSize for device %d-%d, setting to 64", usbdev->bus, usbdev->address); | ||
| 435 | usbdev->wMaxPacketSize = 64; | ||
| 436 | } else { | ||
| 437 | usbmuxd_log(LL_INFO, "Using wMaxPacketSize=%d for device %d-%d", usbdev->wMaxPacketSize, usbdev->bus, usbdev->address); | ||
| 438 | } | ||
| 439 | |||
| 440 | switch (libusb_get_device_speed(dev)) { | ||
| 441 | case LIBUSB_SPEED_LOW: | ||
| 442 | usbdev->speed = 1500000; | ||
| 443 | break; | ||
| 444 | case LIBUSB_SPEED_FULL: | ||
| 445 | usbdev->speed = 12000000; | ||
| 446 | break; | ||
| 447 | case LIBUSB_SPEED_SUPER: | ||
| 448 | usbdev->speed = 5000000000; | ||
| 449 | break; | ||
| 450 | case LIBUSB_SPEED_HIGH: | ||
| 451 | case LIBUSB_SPEED_UNKNOWN: | ||
| 452 | default: | ||
| 453 | usbdev->speed = 480000000; | ||
| 454 | break; | ||
| 455 | } | ||
| 456 | |||
| 457 | usbmuxd_log(LL_INFO, "USB Speed is %g MBit/s for device %d-%d", (double)(usbdev->speed / 1000000.0), usbdev->bus, usbdev->address); | ||
| 458 | |||
| 459 | collection_init(&usbdev->tx_xfers); | ||
| 460 | collection_init(&usbdev->rx_xfers); | ||
| 461 | |||
| 462 | collection_add(&device_list, usbdev); | ||
| 463 | |||
| 464 | if(device_add(usbdev) < 0) { | ||
| 465 | usb_disconnect(usbdev); | ||
| 466 | continue; | ||
| 467 | } | ||
| 468 | |||
| 469 | // Spin up NUM_RX_LOOPS parallel usb data retrieval loops | ||
| 470 | // Old usbmuxds used only 1 rx loop, but that leaves the | ||
| 471 | // USB port sleeping most of the time | ||
| 472 | int rx_loops = NUM_RX_LOOPS; | ||
| 473 | for (rx_loops = NUM_RX_LOOPS; rx_loops > 0; rx_loops--) { | ||
| 474 | if(start_rx_loop(usbdev) < 0) { | ||
| 475 | usbmuxd_log(LL_WARNING, "Failed to start RX loop number %d", NUM_RX_LOOPS - rx_loops); | ||
| 476 | } | ||
| 477 | } | ||
| 478 | |||
| 479 | // Ensure we have at least 1 RX loop going | ||
| 480 | if (rx_loops == NUM_RX_LOOPS) { | ||
| 481 | usbmuxd_log(LL_FATAL, "Failed to start any RX loop for device %d-%d", | ||
| 482 | usbdev->bus, usbdev->address); | ||
| 483 | device_remove(usbdev); | ||
| 484 | usb_disconnect(usbdev); | ||
| 485 | continue; | ||
| 486 | } else if (rx_loops > 0) { | ||
| 487 | usbmuxd_log(LL_WARNING, "Failed to start all %d RX loops. Going on with %d loops. " | ||
| 488 | "This may have negative impact on device read speed.", | ||
| 489 | NUM_RX_LOOPS, NUM_RX_LOOPS - rx_loops); | ||
| 490 | } else { | ||
| 491 | usbmuxd_log(LL_DEBUG, "All %d RX loops started successfully", NUM_RX_LOOPS); | ||
| 492 | } | ||
| 493 | |||
| 494 | valid_count++; | 508 | valid_count++; |
| 495 | } | 509 | } |
| 496 | 510 | ||
| @@ -560,6 +574,7 @@ void usb_autodiscover(int enable) | |||
| 560 | { | 574 | { |
| 561 | usbmuxd_log(LL_DEBUG, "usb polling enable: %d", enable); | 575 | usbmuxd_log(LL_DEBUG, "usb polling enable: %d", enable); |
| 562 | device_polling = enable; | 576 | device_polling = enable; |
| 577 | device_hotplug = enable; | ||
| 563 | } | 578 | } |
| 564 | 579 | ||
| 565 | static int dev_poll_remain_ms(void) | 580 | static int dev_poll_remain_ms(void) |
| @@ -649,6 +664,32 @@ int usb_process_timeout(int msec) | |||
| 649 | return 0; | 664 | return 0; |
| 650 | } | 665 | } |
| 651 | 666 | ||
| 667 | #ifdef HAVE_LIBUSB_HOTPLUG_API | ||
| 668 | static libusb_hotplug_callback_handle usb_hotplug_cb_handle; | ||
| 669 | |||
| 670 | static int usb_hotplug_cb(libusb_context *ctx, libusb_device *device, libusb_hotplug_event event, void *user_data) | ||
| 671 | { | ||
| 672 | if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == event) { | ||
| 673 | if (device_hotplug) { | ||
| 674 | usb_device_add(device); | ||
| 675 | } | ||
| 676 | } else if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) { | ||
| 677 | uint8_t bus = libusb_get_bus_number(device); | ||
| 678 | uint8_t address = libusb_get_device_address(device); | ||
| 679 | FOREACH(struct usb_device *usbdev, &device_list) { | ||
| 680 | if(usbdev->bus == bus && usbdev->address == address) { | ||
| 681 | usbdev->alive = 0; | ||
| 682 | device_remove(usbdev); | ||
| 683 | break; | ||
| 684 | } | ||
| 685 | } ENDFOREACH | ||
| 686 | } else { | ||
| 687 | usbmuxd_log(LL_ERROR, "Unhandled event %d", event); | ||
| 688 | } | ||
| 689 | return 0; | ||
| 690 | } | ||
| 691 | #endif | ||
| 692 | |||
| 652 | int usb_init(void) | 693 | int usb_init(void) |
| 653 | { | 694 | { |
| 654 | int res; | 695 | int res; |
| @@ -665,12 +706,37 @@ int usb_init(void) | |||
| 665 | 706 | ||
| 666 | collection_init(&device_list); | 707 | collection_init(&device_list); |
| 667 | 708 | ||
| 668 | return usb_discover(); | 709 | #ifdef HAVE_LIBUSB_HOTPLUG_API |
| 710 | if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { | ||
| 711 | usbmuxd_log(LL_INFO, "Registering for libusb hotplug events"); | ||
| 712 | res = libusb_hotplug_register_callback(NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, LIBUSB_HOTPLUG_ENUMERATE, VID_APPLE, LIBUSB_HOTPLUG_MATCH_ANY, 0, usb_hotplug_cb, NULL, &usb_hotplug_cb_handle); | ||
| 713 | if (res == LIBUSB_SUCCESS) { | ||
| 714 | device_polling = 0; | ||
| 715 | } else { | ||
| 716 | usbmuxd_log(LL_ERROR, "ERROR: Could not register for libusb hotplug events (%d)", res); | ||
| 717 | } | ||
| 718 | } else { | ||
| 719 | usbmuxd_log(LL_ERROR, "libusb does not support hotplug events"); | ||
| 720 | } | ||
| 721 | #endif | ||
| 722 | if (device_polling) { | ||
| 723 | res = usb_discover(); | ||
| 724 | if (res >= 0) { | ||
| 725 | } | ||
| 726 | } else { | ||
| 727 | res = collection_count(&device_list); | ||
| 728 | } | ||
| 729 | return res; | ||
| 669 | } | 730 | } |
| 670 | 731 | ||
| 671 | void usb_shutdown(void) | 732 | void usb_shutdown(void) |
| 672 | { | 733 | { |
| 673 | usbmuxd_log(LL_DEBUG, "usb_shutdown"); | 734 | usbmuxd_log(LL_DEBUG, "usb_shutdown"); |
| 735 | |||
| 736 | #ifdef HAVE_LIBUSB_HOTPLUG_API | ||
| 737 | libusb_hotplug_deregister_callback(NULL, usb_hotplug_cb_handle); | ||
| 738 | #endif | ||
| 739 | |||
| 674 | FOREACH(struct usb_device *usbdev, &device_list) { | 740 | FOREACH(struct usb_device *usbdev, &device_list) { |
| 675 | device_remove(usbdev); | 741 | device_remove(usbdev); |
| 676 | usb_disconnect(usbdev); | 742 | usb_disconnect(usbdev); |
