summaryrefslogtreecommitdiffstats
path: root/src/usb.c
diff options
context:
space:
mode:
authorGravatar Alexis Ballier2018-01-08 02:00:12 +0100
committerGravatar Nikias Bassen2018-01-08 02:39:38 +0100
commitd29b74db77433a80fa2eb293216e8f572ffe4c57 (patch)
tree2e487667cd3d62532913b3dd8e3c0db465c5b500 /src/usb.c
parent789b16a4a42ab56899092392f1c2d5dde6e9dd34 (diff)
downloadusbmuxd-d29b74db77433a80fa2eb293216e8f572ffe4c57.tar.gz
usbmuxd-d29b74db77433a80fa2eb293216e8f572ffe4c57.tar.bz2
usb: Use libusb asynchronous I/O for getting initial device information.
usb_device_add may now be called from libusb main loop via the hotplug callbacks. No blocking call must occur there and libusb 1.0.21 now returns an error when trying to perform blocking I/O in this callback. Should fix the error when hotpluging a device reported in #81
Diffstat (limited to 'src/usb.c')
-rw-r--r--src/usb.c146
1 files changed, 111 insertions, 35 deletions
diff --git a/src/usb.c b/src/usb.c
index e0fadfd..88d781d 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -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
66static struct collection device_list; 67static 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
262static 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
319static 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
261static int usb_device_add(libusb_device* dev) 347static 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}