diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/usb.c | 146 |
1 files changed, 111 insertions, 35 deletions
| @@ -61,6 +61,7 @@ struct usb_device { | |||
| 61 | int wMaxPacketSize; | 61 | int wMaxPacketSize; |
| 62 | uint64_t speed; | 62 | uint64_t speed; |
| 63 | struct libusb_device_descriptor devdesc; | 63 | struct libusb_device_descriptor devdesc; |
| 64 | unsigned char transfer_buffer[1024 + LIBUSB_CONTROL_SETUP_SIZE]; | ||
| 64 | }; | 65 | }; |
| 65 | 66 | ||
| 66 | static struct collection device_list; | 67 | static struct collection device_list; |
| @@ -258,6 +259,91 @@ static int start_rx_loop(struct usb_device *dev) | |||
| 258 | return 0; | 259 | return 0; |
| 259 | } | 260 | } |
| 260 | 261 | ||
| 262 | static void get_serial_callback(struct libusb_transfer *transfer) | ||
| 263 | { | ||
| 264 | unsigned int di, si; | ||
| 265 | struct usb_device *usbdev = transfer->user_data; | ||
| 266 | |||
| 267 | if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { | ||
| 268 | usbmuxd_log(LL_ERROR, "Failed to request serial for device %d-%d (%i)", usbdev->bus, usbdev->address, transfer->status); | ||
| 269 | libusb_free_transfer(transfer); | ||
| 270 | return; | ||
| 271 | } | ||
| 272 | |||
| 273 | /* De-unicode, taken from libusb */ | ||
| 274 | unsigned char *data = libusb_control_transfer_get_data(transfer); | ||
| 275 | for (di = 0, si = 2; si < data[0] && di < sizeof(usbdev->serial)-1; si += 2) { | ||
| 276 | if ((data[si] & 0x80) || (data[si + 1])) /* non-ASCII */ | ||
| 277 | usbdev->serial[di++] = '?'; | ||
| 278 | else | ||
| 279 | usbdev->serial[di++] = data[si]; | ||
| 280 | } | ||
| 281 | usbdev->serial[di] = 0; | ||
| 282 | |||
| 283 | usbmuxd_log(LL_INFO, "Got serial '%s' for device %d-%d", usbdev->serial, usbdev->bus, usbdev->address); | ||
| 284 | |||
| 285 | libusb_free_transfer(transfer); | ||
| 286 | |||
| 287 | /* Finish setup now */ | ||
| 288 | if(device_add(usbdev) < 0) { | ||
| 289 | usb_disconnect(usbdev); | ||
| 290 | return; | ||
| 291 | } | ||
| 292 | |||
| 293 | // Spin up NUM_RX_LOOPS parallel usb data retrieval loops | ||
| 294 | // Old usbmuxds used only 1 rx loop, but that leaves the | ||
| 295 | // USB port sleeping most of the time | ||
| 296 | int rx_loops = NUM_RX_LOOPS; | ||
| 297 | for (rx_loops = NUM_RX_LOOPS; rx_loops > 0; rx_loops--) { | ||
| 298 | if(start_rx_loop(usbdev) < 0) { | ||
| 299 | usbmuxd_log(LL_WARNING, "Failed to start RX loop number %d", NUM_RX_LOOPS - rx_loops); | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | // Ensure we have at least 1 RX loop going | ||
| 304 | if (rx_loops == NUM_RX_LOOPS) { | ||
| 305 | usbmuxd_log(LL_FATAL, "Failed to start any RX loop for device %d-%d", | ||
| 306 | usbdev->bus, usbdev->address); | ||
| 307 | device_remove(usbdev); | ||
| 308 | usb_disconnect(usbdev); | ||
| 309 | return; | ||
| 310 | } else if (rx_loops > 0) { | ||
| 311 | usbmuxd_log(LL_WARNING, "Failed to start all %d RX loops. Going on with %d loops. " | ||
| 312 | "This may have negative impact on device read speed.", | ||
| 313 | NUM_RX_LOOPS, NUM_RX_LOOPS - rx_loops); | ||
| 314 | } else { | ||
| 315 | usbmuxd_log(LL_DEBUG, "All %d RX loops started successfully", NUM_RX_LOOPS); | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | static void get_langid_callback(struct libusb_transfer *transfer) | ||
| 320 | { | ||
| 321 | int res; | ||
| 322 | struct usb_device *usbdev = transfer->user_data; | ||
| 323 | |||
| 324 | if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { | ||
| 325 | usbmuxd_log(LL_ERROR, "Failed to request lang ID for device %d-%d (%i)", usbdev->bus, | ||
| 326 | usbdev->address, transfer->status); | ||
| 327 | libusb_free_transfer(transfer); | ||
| 328 | return; | ||
| 329 | } | ||
| 330 | |||
| 331 | unsigned char *data = libusb_control_transfer_get_data(transfer); | ||
| 332 | uint16_t langid = (uint16_t)(data[2] | (data[3] << 8)); | ||
| 333 | usbmuxd_log(LL_INFO, "Got lang ID %u for device %d-%d", langid, usbdev->bus, usbdev->address); | ||
| 334 | |||
| 335 | /* re-use the same transfer */ | ||
| 336 | libusb_fill_control_setup(usbdev->transfer_buffer, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR, | ||
| 337 | (uint16_t)((LIBUSB_DT_STRING << 8) | usbdev->devdesc.iSerialNumber), | ||
| 338 | langid, sizeof(usbdev->transfer_buffer)); | ||
| 339 | libusb_fill_control_transfer(transfer, usbdev->dev, usbdev->transfer_buffer, get_serial_callback, usbdev, 1000); | ||
| 340 | |||
| 341 | if((res = libusb_submit_transfer(transfer)) < 0) { | ||
| 342 | usbmuxd_log(LL_ERROR, "Could not request transfer for device %d-%d (%d)", usbdev->bus, usbdev->address, res); | ||
| 343 | libusb_free_transfer(transfer); | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 261 | static int usb_device_add(libusb_device* dev) | 347 | static int usb_device_add(libusb_device* dev) |
| 262 | { | 348 | { |
| 263 | int j, res; | 349 | int j, res; |
| @@ -265,6 +351,7 @@ static int usb_device_add(libusb_device* dev) | |||
| 265 | uint8_t bus = libusb_get_bus_number(dev); | 351 | uint8_t bus = libusb_get_bus_number(dev); |
| 266 | uint8_t address = libusb_get_device_address(dev); | 352 | uint8_t address = libusb_get_device_address(dev); |
| 267 | struct libusb_device_descriptor devdesc; | 353 | struct libusb_device_descriptor devdesc; |
| 354 | struct libusb_transfer *transfer; | ||
| 268 | int found = 0; | 355 | int found = 0; |
| 269 | FOREACH(struct usb_device *usbdev, &device_list) { | 356 | FOREACH(struct usb_device *usbdev, &device_list) { |
| 270 | if(usbdev->bus == bus && usbdev->address == address) { | 357 | if(usbdev->bus == bus && usbdev->address == address) { |
| @@ -287,7 +374,8 @@ static int usb_device_add(libusb_device* dev) | |||
| 287 | return -1; | 374 | return -1; |
| 288 | libusb_device_handle *handle; | 375 | 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); | 376 | 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 | 377 | // No blocking operation can follow: it may be run in the libusb hotplug callback and libusb will refuse any |
| 378 | // blocking call | ||
| 291 | if((res = libusb_open(dev, &handle)) != 0) { | 379 | if((res = libusb_open(dev, &handle)) != 0) { |
| 292 | usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %d", bus, address, res); | 380 | usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %d", bus, address, res); |
| 293 | return -1; | 381 | return -1; |
| @@ -386,14 +474,15 @@ static int usb_device_add(libusb_device* dev) | |||
| 386 | return -1; | 474 | return -1; |
| 387 | } | 475 | } |
| 388 | 476 | ||
| 389 | if((res = libusb_get_string_descriptor_ascii(handle, devdesc.iSerialNumber, (uint8_t *)usbdev->serial, 256)) <= 0) { | 477 | transfer = libusb_alloc_transfer(0); |
| 390 | usbmuxd_log(LL_WARNING, "Could not get serial number for device %d-%d: %d", bus, address, res); | 478 | if(!transfer) { |
| 391 | libusb_release_interface(handle, usbdev->interface); | 479 | usbmuxd_log(LL_WARNING, "Failed to allocate transfer for device %d-%d: %d", bus, address, res); |
| 392 | libusb_close(handle); | 480 | libusb_close(handle); |
| 393 | free(usbdev); | 481 | free(usbdev); |
| 394 | return -1; | 482 | return -1; |
| 395 | } | 483 | } |
| 396 | usbdev->serial[res] = 0; | 484 | |
| 485 | usbdev->serial[0] = 0; | ||
| 397 | usbdev->bus = bus; | 486 | usbdev->bus = bus; |
| 398 | usbdev->address = address; | 487 | usbdev->address = address; |
| 399 | usbdev->devdesc = devdesc; | 488 | usbdev->devdesc = devdesc; |
| @@ -427,40 +516,27 @@ static int usb_device_add(libusb_device* dev) | |||
| 427 | 516 | ||
| 428 | usbmuxd_log(LL_INFO, "USB Speed is %g MBit/s for device %d-%d", (double)(usbdev->speed / 1000000.0), usbdev->bus, usbdev->address); | 517 | usbmuxd_log(LL_INFO, "USB Speed is %g MBit/s for device %d-%d", (double)(usbdev->speed / 1000000.0), usbdev->bus, usbdev->address); |
| 429 | 518 | ||
| 430 | collection_init(&usbdev->tx_xfers); | 519 | /** |
| 431 | collection_init(&usbdev->rx_xfers); | 520 | * From libusb: |
| 432 | 521 | * Asking for the zero'th index is special - it returns a string | |
| 433 | collection_add(&device_list, usbdev); | 522 | * descriptor that contains all the language IDs supported by the |
| 434 | 523 | * device. | |
| 435 | if(device_add(usbdev) < 0) { | 524 | **/ |
| 436 | usb_disconnect(usbdev); | 525 | libusb_fill_control_setup(usbdev->transfer_buffer, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_DT_STRING << 8, 0, sizeof(usbdev->transfer_buffer)); |
| 526 | libusb_fill_control_transfer(transfer, handle, usbdev->transfer_buffer, get_langid_callback, usbdev, 1000); | ||
| 527 | |||
| 528 | if((res = libusb_submit_transfer(transfer)) < 0) { | ||
| 529 | usbmuxd_log(LL_ERROR, "Could not request transfer for device %d-%d (%d)", usbdev->bus, usbdev->address, res); | ||
| 530 | libusb_free_transfer(transfer); | ||
| 531 | libusb_close(handle); | ||
| 532 | free(usbdev); | ||
| 437 | return -1; | 533 | return -1; |
| 438 | } | 534 | } |
| 439 | 535 | ||
| 440 | // Spin up NUM_RX_LOOPS parallel usb data retrieval loops | 536 | collection_init(&usbdev->tx_xfers); |
| 441 | // Old usbmuxds used only 1 rx loop, but that leaves the | 537 | collection_init(&usbdev->rx_xfers); |
| 442 | // USB port sleeping most of the time | ||
| 443 | int rx_loops = NUM_RX_LOOPS; | ||
| 444 | for (rx_loops = NUM_RX_LOOPS; rx_loops > 0; rx_loops--) { | ||
| 445 | if(start_rx_loop(usbdev) < 0) { | ||
| 446 | usbmuxd_log(LL_WARNING, "Failed to start RX loop number %d", NUM_RX_LOOPS - rx_loops); | ||
| 447 | } | ||
| 448 | } | ||
| 449 | 538 | ||
| 450 | // Ensure we have at least 1 RX loop going | 539 | collection_add(&device_list, usbdev); |
| 451 | if (rx_loops == NUM_RX_LOOPS) { | ||
| 452 | usbmuxd_log(LL_FATAL, "Failed to start any RX loop for device %d-%d", | ||
| 453 | usbdev->bus, usbdev->address); | ||
| 454 | device_remove(usbdev); | ||
| 455 | usb_disconnect(usbdev); | ||
| 456 | return -1; | ||
| 457 | } else if (rx_loops > 0) { | ||
| 458 | usbmuxd_log(LL_WARNING, "Failed to start all %d RX loops. Going on with %d loops. " | ||
| 459 | "This may have negative impact on device read speed.", | ||
| 460 | NUM_RX_LOOPS, NUM_RX_LOOPS - rx_loops); | ||
| 461 | } else { | ||
| 462 | usbmuxd_log(LL_DEBUG, "All %d RX loops started successfully", NUM_RX_LOOPS); | ||
| 463 | } | ||
| 464 | 540 | ||
| 465 | return 0; | 541 | return 0; |
| 466 | } | 542 | } |
