diff options
Diffstat (limited to 'src/usb.c')
-rw-r--r-- | src/usb.c | 1084 |
1 files changed, 1084 insertions, 0 deletions
diff --git a/src/usb.c b/src/usb.c new file mode 100644 index 0000000..d3cb17c --- /dev/null +++ b/src/usb.c | |||
@@ -0,0 +1,1084 @@ | |||
1 | /* | ||
2 | * usb.c | ||
3 | * | ||
4 | * Copyright (C) 2009 Hector Martin <hector@marcansoft.com> | ||
5 | * Copyright (C) 2009 Nikias Bassen <nikias@gmx.li> | ||
6 | * Copyright (C) 2009-2020 Martin Szulecki <martin.szulecki@libimobiledevice.org> | ||
7 | * Copyright (C) 2014 Mikkel Kamstrup Erlandsen <mikkel.kamstrup@xamarin.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation, either version 2 or version 3. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
21 | */ | ||
22 | |||
23 | #ifdef HAVE_CONFIG_H | ||
24 | #include <config.h> | ||
25 | #endif | ||
26 | |||
27 | #include <stdio.h> | ||
28 | #include <stdlib.h> | ||
29 | #include <stdint.h> | ||
30 | #include <string.h> | ||
31 | |||
32 | #include <libusb.h> | ||
33 | |||
34 | #include <libimobiledevice-glue/collection.h> | ||
35 | |||
36 | #include "usb.h" | ||
37 | #include "log.h" | ||
38 | #include "device.h" | ||
39 | #include "utils.h" | ||
40 | |||
41 | #if (defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000102)) || (defined(LIBUSBX_API_VERSION) && (LIBUSBX_API_VERSION >= 0x01000102)) | ||
42 | #define HAVE_LIBUSB_HOTPLUG_API 1 | ||
43 | #endif | ||
44 | |||
45 | // interval for device connection/disconnection polling, in milliseconds | ||
46 | // we need this because there is currently no asynchronous device discovery mechanism in libusb | ||
47 | #define DEVICE_POLL_TIME 1000 | ||
48 | |||
49 | // Number of parallel bulk transfers we have running for reading data from the device. | ||
50 | // Older versions of usbmuxd kept only 1, which leads to a mostly dormant USB port. | ||
51 | // 3 seems to be an all round sensible number - giving better read perf than | ||
52 | // Apples usbmuxd, at least. | ||
53 | #define NUM_RX_LOOPS 3 | ||
54 | |||
55 | struct usb_device { | ||
56 | libusb_device_handle *handle; | ||
57 | uint8_t bus, address; | ||
58 | char serial[256]; | ||
59 | int alive; | ||
60 | uint8_t interface, ep_in, ep_out; | ||
61 | struct collection rx_xfers; | ||
62 | struct collection tx_xfers; | ||
63 | int wMaxPacketSize; | ||
64 | uint64_t speed; | ||
65 | struct libusb_device_descriptor devdesc; | ||
66 | }; | ||
67 | |||
68 | struct mode_context { | ||
69 | struct libusb_device* dev; | ||
70 | uint8_t bus, address; | ||
71 | uint8_t bRequest; | ||
72 | uint16_t wValue, wIndex, wLength; | ||
73 | unsigned int timeout; | ||
74 | }; | ||
75 | |||
76 | static struct collection device_list; | ||
77 | |||
78 | static struct timeval next_dev_poll_time; | ||
79 | |||
80 | static int devlist_failures; | ||
81 | static int device_polling; | ||
82 | static int device_hotplug = 1; | ||
83 | |||
84 | static void usb_disconnect(struct usb_device *dev) | ||
85 | { | ||
86 | if(!dev->handle) { | ||
87 | return; | ||
88 | } | ||
89 | |||
90 | // kill the rx xfer and tx xfers and try to make sure the callbacks | ||
91 | // get called before we free the device | ||
92 | FOREACH(struct libusb_transfer *xfer, &dev->rx_xfers) { | ||
93 | usbmuxd_log(LL_DEBUG, "usb_disconnect: cancelling RX xfer %p", xfer); | ||
94 | libusb_cancel_transfer(xfer); | ||
95 | } ENDFOREACH | ||
96 | |||
97 | FOREACH(struct libusb_transfer *xfer, &dev->tx_xfers) { | ||
98 | usbmuxd_log(LL_DEBUG, "usb_disconnect: cancelling TX xfer %p", xfer); | ||
99 | libusb_cancel_transfer(xfer); | ||
100 | } ENDFOREACH | ||
101 | |||
102 | // Busy-wait until all xfers are closed | ||
103 | while(collection_count(&dev->rx_xfers) || collection_count(&dev->tx_xfers)) { | ||
104 | struct timeval tv; | ||
105 | int res; | ||
106 | |||
107 | tv.tv_sec = 0; | ||
108 | tv.tv_usec = 1000; | ||
109 | if((res = libusb_handle_events_timeout(NULL, &tv)) < 0) { | ||
110 | usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout for usb_disconnect failed: %s", libusb_error_name(res)); | ||
111 | break; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | collection_free(&dev->tx_xfers); | ||
116 | collection_free(&dev->rx_xfers); | ||
117 | libusb_release_interface(dev->handle, dev->interface); | ||
118 | libusb_close(dev->handle); | ||
119 | dev->handle = NULL; | ||
120 | collection_remove(&device_list, dev); | ||
121 | free(dev); | ||
122 | } | ||
123 | |||
124 | static void reap_dead_devices(void) { | ||
125 | FOREACH(struct usb_device *usbdev, &device_list) { | ||
126 | if(!usbdev->alive) { | ||
127 | device_remove(usbdev); | ||
128 | usb_disconnect(usbdev); | ||
129 | } | ||
130 | } ENDFOREACH | ||
131 | } | ||
132 | |||
133 | // Callback from write operation | ||
134 | static void tx_callback(struct libusb_transfer *xfer) | ||
135 | { | ||
136 | struct usb_device *dev = xfer->user_data; | ||
137 | usbmuxd_log(LL_SPEW, "TX callback dev %d-%d len %d -> %d status %d", dev->bus, dev->address, xfer->length, xfer->actual_length, xfer->status); | ||
138 | if(xfer->status != LIBUSB_TRANSFER_COMPLETED) { | ||
139 | switch(xfer->status) { | ||
140 | case LIBUSB_TRANSFER_COMPLETED: //shut up compiler | ||
141 | case LIBUSB_TRANSFER_ERROR: | ||
142 | // funny, this happens when we disconnect the device while waiting for a transfer, sometimes | ||
143 | usbmuxd_log(LL_INFO, "Device %d-%d TX aborted due to error or disconnect", dev->bus, dev->address); | ||
144 | break; | ||
145 | case LIBUSB_TRANSFER_TIMED_OUT: | ||
146 | usbmuxd_log(LL_ERROR, "TX transfer timed out for device %d-%d", dev->bus, dev->address); | ||
147 | break; | ||
148 | case LIBUSB_TRANSFER_CANCELLED: | ||
149 | usbmuxd_log(LL_DEBUG, "Device %d-%d TX transfer cancelled", dev->bus, dev->address); | ||
150 | break; | ||
151 | case LIBUSB_TRANSFER_STALL: | ||
152 | usbmuxd_log(LL_ERROR, "TX transfer stalled for device %d-%d", dev->bus, dev->address); | ||
153 | break; | ||
154 | case LIBUSB_TRANSFER_NO_DEVICE: | ||
155 | // other times, this happens, and also even when we abort the transfer after device removal | ||
156 | usbmuxd_log(LL_INFO, "Device %d-%d TX aborted due to disconnect", dev->bus, dev->address); | ||
157 | break; | ||
158 | case LIBUSB_TRANSFER_OVERFLOW: | ||
159 | usbmuxd_log(LL_ERROR, "TX transfer overflow for device %d-%d", dev->bus, dev->address); | ||
160 | break; | ||
161 | // and nothing happens (this never gets called) if the device is freed after a disconnect! (bad) | ||
162 | default: | ||
163 | // this should never be reached. | ||
164 | break; | ||
165 | } | ||
166 | // we can't usb_disconnect here due to a deadlock, so instead mark it as dead and reap it after processing events | ||
167 | // we'll do device_remove there too | ||
168 | dev->alive = 0; | ||
169 | } | ||
170 | if(xfer->buffer) | ||
171 | free(xfer->buffer); | ||
172 | collection_remove(&dev->tx_xfers, xfer); | ||
173 | libusb_free_transfer(xfer); | ||
174 | } | ||
175 | |||
176 | int usb_send(struct usb_device *dev, const unsigned char *buf, int length) | ||
177 | { | ||
178 | int res; | ||
179 | struct libusb_transfer *xfer = libusb_alloc_transfer(0); | ||
180 | libusb_fill_bulk_transfer(xfer, dev->handle, dev->ep_out, (void*)buf, length, tx_callback, dev, 0); | ||
181 | if((res = libusb_submit_transfer(xfer)) < 0) { | ||
182 | usbmuxd_log(LL_ERROR, "Failed to submit TX transfer %p len %d to device %d-%d: %s", buf, length, dev->bus, dev->address, libusb_error_name(res)); | ||
183 | libusb_free_transfer(xfer); | ||
184 | return res; | ||
185 | } | ||
186 | collection_add(&dev->tx_xfers, xfer); | ||
187 | if (length % dev->wMaxPacketSize == 0) { | ||
188 | usbmuxd_log(LL_DEBUG, "Send ZLP"); | ||
189 | // Send Zero Length Packet | ||
190 | xfer = libusb_alloc_transfer(0); | ||
191 | void *buffer = malloc(1); | ||
192 | libusb_fill_bulk_transfer(xfer, dev->handle, dev->ep_out, buffer, 0, tx_callback, dev, 0); | ||
193 | if((res = libusb_submit_transfer(xfer)) < 0) { | ||
194 | usbmuxd_log(LL_ERROR, "Failed to submit TX ZLP transfer to device %d-%d: %s", dev->bus, dev->address, libusb_error_name(res)); | ||
195 | libusb_free_transfer(xfer); | ||
196 | return res; | ||
197 | } | ||
198 | collection_add(&dev->tx_xfers, xfer); | ||
199 | } | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | // Callback from read operation | ||
204 | // Under normal operation this issues a new read transfer request immediately, | ||
205 | // doing a kind of read-callback loop | ||
206 | static void rx_callback(struct libusb_transfer *xfer) | ||
207 | { | ||
208 | struct usb_device *dev = xfer->user_data; | ||
209 | usbmuxd_log(LL_SPEW, "RX callback dev %d-%d len %d status %d", dev->bus, dev->address, xfer->actual_length, xfer->status); | ||
210 | if(xfer->status == LIBUSB_TRANSFER_COMPLETED) { | ||
211 | device_data_input(dev, xfer->buffer, xfer->actual_length); | ||
212 | libusb_submit_transfer(xfer); | ||
213 | } else { | ||
214 | switch(xfer->status) { | ||
215 | case LIBUSB_TRANSFER_COMPLETED: //shut up compiler | ||
216 | case LIBUSB_TRANSFER_ERROR: | ||
217 | // funny, this happens when we disconnect the device while waiting for a transfer, sometimes | ||
218 | usbmuxd_log(LL_INFO, "Device %d-%d RX aborted due to error or disconnect", dev->bus, dev->address); | ||
219 | break; | ||
220 | case LIBUSB_TRANSFER_TIMED_OUT: | ||
221 | usbmuxd_log(LL_ERROR, "RX transfer timed out for device %d-%d", dev->bus, dev->address); | ||
222 | break; | ||
223 | case LIBUSB_TRANSFER_CANCELLED: | ||
224 | usbmuxd_log(LL_DEBUG, "Device %d-%d RX transfer cancelled", dev->bus, dev->address); | ||
225 | break; | ||
226 | case LIBUSB_TRANSFER_STALL: | ||
227 | usbmuxd_log(LL_ERROR, "RX transfer stalled for device %d-%d", dev->bus, dev->address); | ||
228 | break; | ||
229 | case LIBUSB_TRANSFER_NO_DEVICE: | ||
230 | // other times, this happens, and also even when we abort the transfer after device removal | ||
231 | usbmuxd_log(LL_INFO, "Device %d-%d RX aborted due to disconnect", dev->bus, dev->address); | ||
232 | break; | ||
233 | case LIBUSB_TRANSFER_OVERFLOW: | ||
234 | usbmuxd_log(LL_ERROR, "RX transfer overflow for device %d-%d", dev->bus, dev->address); | ||
235 | break; | ||
236 | // and nothing happens (this never gets called) if the device is freed after a disconnect! (bad) | ||
237 | default: | ||
238 | // this should never be reached. | ||
239 | break; | ||
240 | } | ||
241 | |||
242 | free(xfer->buffer); | ||
243 | collection_remove(&dev->rx_xfers, xfer); | ||
244 | libusb_free_transfer(xfer); | ||
245 | |||
246 | // we can't usb_disconnect here due to a deadlock, so instead mark it as dead and reap it after processing events | ||
247 | // we'll do device_remove there too | ||
248 | dev->alive = 0; | ||
249 | } | ||
250 | } | ||
251 | |||
252 | // Start a read-callback loop for this device | ||
253 | static int start_rx_loop(struct usb_device *dev) | ||
254 | { | ||
255 | int res; | ||
256 | void *buf; | ||
257 | struct libusb_transfer *xfer = libusb_alloc_transfer(0); | ||
258 | buf = malloc(USB_MRU); | ||
259 | libusb_fill_bulk_transfer(xfer, dev->handle, dev->ep_in, buf, USB_MRU, rx_callback, dev, 0); | ||
260 | if((res = libusb_submit_transfer(xfer)) != 0) { | ||
261 | usbmuxd_log(LL_ERROR, "Failed to submit RX transfer to device %d-%d: %s", dev->bus, dev->address, libusb_error_name(res)); | ||
262 | libusb_free_transfer(xfer); | ||
263 | return res; | ||
264 | } | ||
265 | |||
266 | collection_add(&dev->rx_xfers, xfer); | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static void get_serial_callback(struct libusb_transfer *transfer) | ||
272 | { | ||
273 | unsigned int di, si; | ||
274 | struct usb_device *usbdev = transfer->user_data; | ||
275 | |||
276 | if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { | ||
277 | usbmuxd_log(LL_ERROR, "Failed to request serial for device %d-%d (%i)", usbdev->bus, usbdev->address, transfer->status); | ||
278 | libusb_free_transfer(transfer); | ||
279 | return; | ||
280 | } | ||
281 | |||
282 | /* De-unicode, taken from libusb */ | ||
283 | unsigned char *data = libusb_control_transfer_get_data(transfer); | ||
284 | for (di = 0, si = 2; si < data[0] && di < sizeof(usbdev->serial)-1; si += 2) { | ||
285 | if ((data[si] & 0x80) || (data[si + 1])) /* non-ASCII */ | ||
286 | usbdev->serial[di++] = '?'; | ||
287 | else if (data[si] == '\0') | ||
288 | break; | ||
289 | else | ||
290 | usbdev->serial[di++] = data[si]; | ||
291 | } | ||
292 | usbdev->serial[di] = '\0'; | ||
293 | |||
294 | usbmuxd_log(LL_INFO, "Got serial '%s' for device %d-%d", usbdev->serial, usbdev->bus, usbdev->address); | ||
295 | |||
296 | libusb_free_transfer(transfer); | ||
297 | |||
298 | /* new style UDID: add hyphen between first 8 and following 16 digits */ | ||
299 | if (di == 24) { | ||
300 | memmove(&usbdev->serial[9], &usbdev->serial[8], 16); | ||
301 | usbdev->serial[8] = '-'; | ||
302 | usbdev->serial[di+1] = '\0'; | ||
303 | } | ||
304 | |||
305 | /* Finish setup now */ | ||
306 | if(device_add(usbdev) < 0) { | ||
307 | usb_disconnect(usbdev); | ||
308 | return; | ||
309 | } | ||
310 | |||
311 | // Spin up NUM_RX_LOOPS parallel usb data retrieval loops | ||
312 | // Old usbmuxds used only 1 rx loop, but that leaves the | ||
313 | // USB port sleeping most of the time | ||
314 | int rx_loops = NUM_RX_LOOPS; | ||
315 | for (rx_loops = NUM_RX_LOOPS; rx_loops > 0; rx_loops--) { | ||
316 | if(start_rx_loop(usbdev) < 0) { | ||
317 | usbmuxd_log(LL_WARNING, "Failed to start RX loop number %d", NUM_RX_LOOPS - rx_loops); | ||
318 | break; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | // Ensure we have at least 1 RX loop going | ||
323 | if (rx_loops == NUM_RX_LOOPS) { | ||
324 | usbmuxd_log(LL_FATAL, "Failed to start any RX loop for device %d-%d", | ||
325 | usbdev->bus, usbdev->address); | ||
326 | device_remove(usbdev); | ||
327 | usb_disconnect(usbdev); | ||
328 | return; | ||
329 | } else if (rx_loops > 0) { | ||
330 | usbmuxd_log(LL_WARNING, "Failed to start all %d RX loops. Going on with %d loops. " | ||
331 | "This may have negative impact on device read speed.", | ||
332 | NUM_RX_LOOPS, NUM_RX_LOOPS - rx_loops); | ||
333 | } else { | ||
334 | usbmuxd_log(LL_DEBUG, "All %d RX loops started successfully", NUM_RX_LOOPS); | ||
335 | } | ||
336 | } | ||
337 | |||
338 | static void get_langid_callback(struct libusb_transfer *transfer) | ||
339 | { | ||
340 | int res; | ||
341 | struct usb_device *usbdev = transfer->user_data; | ||
342 | |||
343 | transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER; | ||
344 | |||
345 | if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { | ||
346 | usbmuxd_log(LL_ERROR, "Failed to request lang ID for device %d-%d (%i)", usbdev->bus, | ||
347 | usbdev->address, transfer->status); | ||
348 | libusb_free_transfer(transfer); | ||
349 | return; | ||
350 | } | ||
351 | |||
352 | unsigned char *data = libusb_control_transfer_get_data(transfer); | ||
353 | uint16_t langid = (uint16_t)(data[2] | (data[3] << 8)); | ||
354 | usbmuxd_log(LL_INFO, "Got lang ID %u for device %d-%d", langid, usbdev->bus, usbdev->address); | ||
355 | |||
356 | /* re-use the same transfer */ | ||
357 | libusb_fill_control_setup(transfer->buffer, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR, | ||
358 | (uint16_t)((LIBUSB_DT_STRING << 8) | usbdev->devdesc.iSerialNumber), | ||
359 | langid, 1024 + LIBUSB_CONTROL_SETUP_SIZE); | ||
360 | libusb_fill_control_transfer(transfer, usbdev->handle, transfer->buffer, get_serial_callback, usbdev, 1000); | ||
361 | |||
362 | if((res = libusb_submit_transfer(transfer)) < 0) { | ||
363 | usbmuxd_log(LL_ERROR, "Could not request transfer for device %d-%d: %s", usbdev->bus, usbdev->address, libusb_error_name(res)); | ||
364 | libusb_free_transfer(transfer); | ||
365 | } | ||
366 | } | ||
367 | |||
368 | static int submit_vendor_specific(struct libusb_device_handle *handle, struct mode_context *context, libusb_transfer_cb_fn callback) | ||
369 | { | ||
370 | struct libusb_transfer* ctrl_transfer = libusb_alloc_transfer(0); | ||
371 | int ret = 0; | ||
372 | unsigned char* buffer = calloc(LIBUSB_CONTROL_SETUP_SIZE + context->wLength, 1); | ||
373 | uint8_t bRequestType = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE; | ||
374 | libusb_fill_control_setup(buffer, bRequestType, context->bRequest, context->wValue, context->wIndex, context->wLength); | ||
375 | |||
376 | ctrl_transfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER; | ||
377 | libusb_fill_control_transfer(ctrl_transfer, handle, buffer, callback, context, context->timeout); | ||
378 | |||
379 | ret = libusb_submit_transfer(ctrl_transfer); | ||
380 | return ret; | ||
381 | } | ||
382 | |||
383 | static struct usb_device* find_device(int bus, int address) | ||
384 | { | ||
385 | FOREACH(struct usb_device *usbdev, &device_list) { | ||
386 | if(usbdev->bus == bus && usbdev->address == address) { | ||
387 | return usbdev; | ||
388 | } | ||
389 | } ENDFOREACH | ||
390 | return NULL; | ||
391 | } | ||
392 | |||
393 | /// @brief guess the current mode | ||
394 | /// @param dev | ||
395 | /// @param usbdev | ||
396 | /// @param handle | ||
397 | /// @return 0 - undetermined, 1 - initial, 2 - valeria, 3 - cdc_ncm | ||
398 | static int guess_mode(struct libusb_device* dev, struct usb_device *usbdev) | ||
399 | { | ||
400 | int res, j; | ||
401 | int has_valeria = 0, has_cdc_ncm = 0, has_usbmux = 0; | ||
402 | struct libusb_device_descriptor devdesc = usbdev->devdesc; | ||
403 | struct libusb_config_descriptor *config; | ||
404 | int bus = usbdev->bus; | ||
405 | int address = usbdev->address; | ||
406 | |||
407 | if(devdesc.bNumConfigurations <= 4) { | ||
408 | // Assume this is initial mode | ||
409 | return 1; | ||
410 | } | ||
411 | |||
412 | if(devdesc.bNumConfigurations != 5) { | ||
413 | // No known modes with more then 5 configurations | ||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | if((res = libusb_get_config_descriptor_by_value(dev, 5, &config)) != 0) { | ||
418 | usbmuxd_log(LL_NOTICE, "Could not get configuration 5 descriptor for device %i-%i: %s", bus, address, libusb_error_name(res)); | ||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | // Require both usbmux and one of the other interfaces to determine this is a valid configuration | ||
423 | for(j = 0 ; j < config->bNumInterfaces ; j++) { | ||
424 | const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0]; | ||
425 | if(intf->bInterfaceClass == INTERFACE_CLASS && | ||
426 | intf->bInterfaceSubClass == 42 && | ||
427 | intf->bInterfaceProtocol == 255) { | ||
428 | has_valeria = 1; | ||
429 | } | ||
430 | // https://github.com/torvalds/linux/blob/72a85e2b0a1e1e6fb4ee51ae902730212b2de25c/include/uapi/linux/usb/cdc.h#L22 | ||
431 | // 2 for Communication class, 0xd for CDC NCM subclass | ||
432 | if(intf->bInterfaceClass == 2 && | ||
433 | intf->bInterfaceSubClass == 0xd) { | ||
434 | has_cdc_ncm = 1; | ||
435 | } | ||
436 | if(intf->bInterfaceClass == INTERFACE_CLASS && | ||
437 | intf->bInterfaceSubClass == INTERFACE_SUBCLASS && | ||
438 | intf->bInterfaceProtocol == INTERFACE_PROTOCOL) { | ||
439 | has_usbmux = 1; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | libusb_free_config_descriptor(config); | ||
444 | |||
445 | if(has_valeria && has_usbmux) { | ||
446 | usbmuxd_log(LL_NOTICE, "Found Valeria and Apple USB Multiplexor in device %i-%i configuration 5", bus, address); | ||
447 | return 2; | ||
448 | } | ||
449 | |||
450 | if(has_cdc_ncm && has_usbmux) { | ||
451 | usbmuxd_log(LL_NOTICE, "Found CDC-NCM and Apple USB Multiplexor in device %i-%i configuration 5", bus, address); | ||
452 | return 3; | ||
453 | } | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | /// @brief Finds and sets the valid configuration, interface and endpoints on the usb_device | ||
459 | static int set_valid_configuration(struct libusb_device* dev, struct usb_device *usbdev, struct libusb_device_handle *handle) | ||
460 | { | ||
461 | int j, k, res, found = 0; | ||
462 | struct libusb_config_descriptor *config; | ||
463 | const struct libusb_interface_descriptor *intf; | ||
464 | struct libusb_device_descriptor devdesc = usbdev->devdesc; | ||
465 | int bus = usbdev->bus; | ||
466 | int address = usbdev->address; | ||
467 | int current_config = 0; | ||
468 | |||
469 | if((res = libusb_get_configuration(handle, ¤t_config)) != 0) { | ||
470 | usbmuxd_log(LL_WARNING, "Could not get current configuration for device %d-%d: %s", bus, address, libusb_error_name(res)); | ||
471 | return -1; | ||
472 | } | ||
473 | |||
474 | for(j = devdesc.bNumConfigurations ; j > 0 ; j--) { | ||
475 | if((res = libusb_get_config_descriptor_by_value(dev, j, &config)) != 0) { | ||
476 | usbmuxd_log(LL_NOTICE, "Could not get configuration %i descriptor for device %i-%i: %s", j, bus, address, libusb_error_name(res)); | ||
477 | continue; | ||
478 | } | ||
479 | for(k = 0 ; k < config->bNumInterfaces ; k++) { | ||
480 | intf = &config->interface[k].altsetting[0]; | ||
481 | if(intf->bInterfaceClass == INTERFACE_CLASS || | ||
482 | intf->bInterfaceSubClass == INTERFACE_SUBCLASS || | ||
483 | intf->bInterfaceProtocol == INTERFACE_PROTOCOL) { | ||
484 | usbmuxd_log(LL_NOTICE, "Found usbmux interface for device %i-%i: %i", bus, address, intf->bInterfaceNumber); | ||
485 | if(intf->bNumEndpoints != 2) { | ||
486 | usbmuxd_log(LL_WARNING, "Endpoint count mismatch for interface %i of device %i-%i", intf->bInterfaceNumber, bus, address); | ||
487 | continue; | ||
488 | } | ||
489 | if((intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT && | ||
490 | (intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) { | ||
491 | usbdev->interface = intf->bInterfaceNumber; | ||
492 | usbdev->ep_out = intf->endpoint[0].bEndpointAddress; | ||
493 | usbdev->ep_in = intf->endpoint[1].bEndpointAddress; | ||
494 | 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); | ||
495 | found = 1; | ||
496 | break; | ||
497 | } else if((intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT && | ||
498 | (intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) { | ||
499 | usbdev->interface = intf->bInterfaceNumber; | ||
500 | usbdev->ep_out = intf->endpoint[1].bEndpointAddress; | ||
501 | usbdev->ep_in = intf->endpoint[0].bEndpointAddress; | ||
502 | 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); | ||
503 | found = 1; | ||
504 | break; | ||
505 | } else { | ||
506 | usbmuxd_log(LL_WARNING, "Endpoint type mismatch for interface %i of device %i-%i", intf->bInterfaceNumber, bus, address); | ||
507 | } | ||
508 | } | ||
509 | } | ||
510 | if(!found) { | ||
511 | libusb_free_config_descriptor(config); | ||
512 | continue; | ||
513 | } | ||
514 | // If set configuration is required, try to first detach all kernel drivers | ||
515 | if (current_config == 0) { | ||
516 | usbmuxd_log(LL_DEBUG, "Device %d-%d is unconfigured", bus, address); | ||
517 | } | ||
518 | if(current_config == 0 || config->bConfigurationValue != current_config) { | ||
519 | usbmuxd_log(LL_NOTICE, "Changing configuration of device %i-%i: %i -> %i", bus, address, current_config, config->bConfigurationValue); | ||
520 | for(k=0 ; k < config->bNumInterfaces ; k++) { | ||
521 | const struct libusb_interface_descriptor *intf1 = &config->interface[k].altsetting[0]; | ||
522 | if((res = libusb_kernel_driver_active(handle, intf1->bInterfaceNumber)) < 0) { | ||
523 | 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)); | ||
524 | continue; | ||
525 | } | ||
526 | if(res == 1) { | ||
527 | usbmuxd_log(LL_INFO, "Detaching kernel driver for device %d-%d, interface %d", bus, address, intf1->bInterfaceNumber); | ||
528 | if((res = libusb_detach_kernel_driver(handle, intf1->bInterfaceNumber)) < 0) { | ||
529 | usbmuxd_log(LL_WARNING, "Could not detach kernel driver, configuration change will probably fail! %s", libusb_error_name(res)); | ||
530 | continue; | ||
531 | } | ||
532 | } | ||
533 | } | ||
534 | if((res = libusb_set_configuration(handle, j)) != 0) { | ||
535 | usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %s", j, bus, address, libusb_error_name(res)); | ||
536 | libusb_free_config_descriptor(config); | ||
537 | continue; | ||
538 | } | ||
539 | } | ||
540 | |||
541 | libusb_free_config_descriptor(config); | ||
542 | break; | ||
543 | } | ||
544 | |||
545 | if(!found) { | ||
546 | usbmuxd_log(LL_WARNING, "Could not find a suitable USB interface for device %i-%i", bus, address); | ||
547 | return -1; | ||
548 | } | ||
549 | |||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | static void device_complete_initialization(struct mode_context *context, struct libusb_device_handle *handle) | ||
554 | { | ||
555 | struct usb_device *usbdev = find_device(context->bus, context->address); | ||
556 | if(!usbdev) { | ||
557 | usbmuxd_log(LL_ERROR, "Device %d-%d is missing from device list, aborting initialization", context->bus, context->address); | ||
558 | return; | ||
559 | } | ||
560 | struct libusb_device *dev = context->dev; | ||
561 | struct libusb_device_descriptor devdesc = usbdev->devdesc; | ||
562 | int bus = context->bus; | ||
563 | int address = context->address; | ||
564 | int res; | ||
565 | struct libusb_transfer *transfer; | ||
566 | |||
567 | if((res = set_valid_configuration(dev, usbdev, handle)) != 0) { | ||
568 | usbdev->alive = 0; | ||
569 | return; | ||
570 | } | ||
571 | |||
572 | if((res = libusb_claim_interface(handle, usbdev->interface)) != 0) { | ||
573 | usbmuxd_log(LL_WARNING, "Could not claim interface %d for device %d-%d: %s", usbdev->interface, bus, address, libusb_error_name(res)); | ||
574 | usbdev->alive = 0; | ||
575 | return; | ||
576 | } | ||
577 | |||
578 | transfer = libusb_alloc_transfer(0); | ||
579 | if(!transfer) { | ||
580 | usbmuxd_log(LL_WARNING, "Failed to allocate transfer for device %d-%d: %s", bus, address, libusb_error_name(res)); | ||
581 | usbdev->alive = 0; | ||
582 | return; | ||
583 | } | ||
584 | |||
585 | unsigned char *transfer_buffer = malloc(1024 + LIBUSB_CONTROL_SETUP_SIZE + 8); | ||
586 | if (!transfer_buffer) { | ||
587 | usbmuxd_log(LL_WARNING, "Failed to allocate transfer buffer for device %d-%d: %s", bus, address, libusb_error_name(res)); | ||
588 | usbdev->alive = 0; | ||
589 | return; | ||
590 | } | ||
591 | memset(transfer_buffer, '\0', 1024 + LIBUSB_CONTROL_SETUP_SIZE + 8); | ||
592 | |||
593 | usbdev->serial[0] = 0; | ||
594 | usbdev->bus = bus; | ||
595 | usbdev->address = address; | ||
596 | usbdev->devdesc = devdesc; | ||
597 | usbdev->speed = 480000000; | ||
598 | usbdev->handle = handle; | ||
599 | usbdev->alive = 1; | ||
600 | usbdev->wMaxPacketSize = libusb_get_max_packet_size(dev, usbdev->ep_out); | ||
601 | if (usbdev->wMaxPacketSize <= 0) { | ||
602 | usbmuxd_log(LL_ERROR, "Could not determine wMaxPacketSize for device %d-%d, setting to 64", usbdev->bus, usbdev->address); | ||
603 | usbdev->wMaxPacketSize = 64; | ||
604 | } else { | ||
605 | usbmuxd_log(LL_INFO, "Using wMaxPacketSize=%d for device %d-%d", usbdev->wMaxPacketSize, usbdev->bus, usbdev->address); | ||
606 | } | ||
607 | |||
608 | switch (libusb_get_device_speed(dev)) { | ||
609 | case LIBUSB_SPEED_LOW: | ||
610 | usbdev->speed = 1500000; | ||
611 | break; | ||
612 | case LIBUSB_SPEED_FULL: | ||
613 | usbdev->speed = 12000000; | ||
614 | break; | ||
615 | case LIBUSB_SPEED_SUPER: | ||
616 | usbdev->speed = 5000000000; | ||
617 | break; | ||
618 | case LIBUSB_SPEED_HIGH: | ||
619 | case LIBUSB_SPEED_UNKNOWN: | ||
620 | default: | ||
621 | usbdev->speed = 480000000; | ||
622 | break; | ||
623 | } | ||
624 | |||
625 | usbmuxd_log(LL_INFO, "USB Speed is %g MBit/s for device %d-%d", (double)(usbdev->speed / 1000000.0), usbdev->bus, usbdev->address); | ||
626 | |||
627 | /** | ||
628 | * From libusb: | ||
629 | * Asking for the zero'th index is special - it returns a string | ||
630 | * descriptor that contains all the language IDs supported by the | ||
631 | * device. | ||
632 | **/ | ||
633 | libusb_fill_control_setup(transfer_buffer, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_DT_STRING << 8, 0, 1024 + LIBUSB_CONTROL_SETUP_SIZE); | ||
634 | libusb_fill_control_transfer(transfer, handle, transfer_buffer, get_langid_callback, usbdev, 1000); | ||
635 | |||
636 | if((res = libusb_submit_transfer(transfer)) < 0) { | ||
637 | usbmuxd_log(LL_ERROR, "Could not request transfer for device %d-%d: %s", usbdev->bus, usbdev->address, libusb_error_name(res)); | ||
638 | libusb_free_transfer(transfer); | ||
639 | free(transfer_buffer); | ||
640 | usbdev->alive = 0; | ||
641 | return; | ||
642 | } | ||
643 | } | ||
644 | |||
645 | static void switch_mode_cb(struct libusb_transfer* transfer) | ||
646 | { | ||
647 | // For old devices not supporting mode swtich, if anything goes wrong - continue in current mode | ||
648 | struct mode_context* context = transfer->user_data; | ||
649 | struct usb_device *dev = find_device(context->bus, context->address); | ||
650 | if(!dev) { | ||
651 | usbmuxd_log(LL_WARNING, "Device %d-%d is missing from device list", context->bus, context->address); | ||
652 | } | ||
653 | if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { | ||
654 | usbmuxd_log(LL_ERROR, "Failed to request mode switch for device %i-%i (%i). Completing initialization in current mode", | ||
655 | context->bus, context->address, transfer->status); | ||
656 | device_complete_initialization(context, transfer->dev_handle); | ||
657 | } | ||
658 | else { | ||
659 | unsigned char *data = libusb_control_transfer_get_data(transfer); | ||
660 | if(data[0] != 0) { | ||
661 | usbmuxd_log(LL_INFO, "Received unexpected response for device %i-%i mode switch (%i). Completing initialization in current mode", | ||
662 | context->bus, context->address, data[0]); | ||
663 | device_complete_initialization(context, transfer->dev_handle); | ||
664 | } | ||
665 | } | ||
666 | free(context); | ||
667 | if(transfer->buffer) | ||
668 | free(transfer->buffer); | ||
669 | } | ||
670 | |||
671 | static void get_mode_cb(struct libusb_transfer* transfer) | ||
672 | { | ||
673 | // For old devices not supporting mode swtich, if anything goes wrong - continue in current mode | ||
674 | int res; | ||
675 | struct mode_context* context = transfer->user_data; | ||
676 | struct usb_device *dev = find_device(context->bus, context->address); | ||
677 | if(!dev) { | ||
678 | usbmuxd_log(LL_ERROR, "Device %d-%d is missing from device list, aborting mode switch", context->bus, context->address); | ||
679 | free(context); | ||
680 | return; | ||
681 | } | ||
682 | |||
683 | if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { | ||
684 | usbmuxd_log(LL_ERROR, "Failed to request get mode for device %i-%i (%i). Completing initialization in current mode", | ||
685 | context->bus, context->address, transfer->status); | ||
686 | device_complete_initialization(context, transfer->dev_handle); | ||
687 | free(context); | ||
688 | return; | ||
689 | } | ||
690 | |||
691 | unsigned char *data = libusb_control_transfer_get_data(transfer); | ||
692 | |||
693 | char* desired_mode_char = getenv(ENV_DEVICE_MODE); | ||
694 | int desired_mode = desired_mode_char ? atoi(desired_mode_char) : 3; | ||
695 | int guessed_mode = guess_mode(context->dev, dev); | ||
696 | |||
697 | // Response is 3:3:3:0 for initial mode, 5:3:3:0 otherwise. | ||
698 | usbmuxd_log(LL_INFO, "Received response %i:%i:%i:%i for get_mode request for device %i-%i", data[0], data[1], data[2], data[3], context->bus, context->address); | ||
699 | if(desired_mode >= 1 && desired_mode <= 3 && | ||
700 | guessed_mode > 0 && // do not switch mode if guess failed | ||
701 | guessed_mode != desired_mode) { | ||
702 | usbmuxd_log(LL_WARNING, "Switching device %i-%i mode to %i", context->bus, context->address, desired_mode); | ||
703 | |||
704 | context->bRequest = APPLE_VEND_SPECIFIC_SET_MODE; | ||
705 | context->wValue = 0; | ||
706 | context->wIndex = desired_mode; | ||
707 | context->wLength = 1; | ||
708 | |||
709 | if((res = submit_vendor_specific(transfer->dev_handle, context, switch_mode_cb)) != 0) { | ||
710 | usbmuxd_log(LL_WARNING, "Could not request to switch mode %i for device %i-%i (%i)", context->wIndex, context->bus, context->address, res); | ||
711 | dev->alive = 0; | ||
712 | free(context); | ||
713 | } | ||
714 | } | ||
715 | else { | ||
716 | usbmuxd_log(LL_WARNING, "Skipping switch device %i-%i mode from %i to %i", context->bus, context->address, guessed_mode, desired_mode); | ||
717 | device_complete_initialization(context, transfer->dev_handle); | ||
718 | free(context); | ||
719 | } | ||
720 | if(transfer->buffer) | ||
721 | free(transfer->buffer); | ||
722 | } | ||
723 | |||
724 | static int usb_device_add(libusb_device* dev) | ||
725 | { | ||
726 | int res; | ||
727 | // the following are non-blocking operations on the device list | ||
728 | uint8_t bus = libusb_get_bus_number(dev); | ||
729 | uint8_t address = libusb_get_device_address(dev); | ||
730 | struct libusb_device_descriptor devdesc; | ||
731 | struct usb_device *usbdev = find_device(bus, address); | ||
732 | if(usbdev) { | ||
733 | usbdev->alive = 1; | ||
734 | return 0; //device already found | ||
735 | } | ||
736 | |||
737 | if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) { | ||
738 | usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %s", bus, address, libusb_error_name(res)); | ||
739 | return -1; | ||
740 | } | ||
741 | if(devdesc.idVendor != VID_APPLE) | ||
742 | return -1; | ||
743 | if((devdesc.idProduct != PID_APPLE_T2_COPROCESSOR) && | ||
744 | ((devdesc.idProduct < PID_APPLE_SILICON_RESTORE_LOW) || | ||
745 | (devdesc.idProduct > PID_APPLE_SILICON_RESTORE_MAX)) && | ||
746 | ((devdesc.idProduct < PID_RANGE_LOW) || | ||
747 | (devdesc.idProduct > PID_RANGE_MAX))) | ||
748 | return -1; | ||
749 | libusb_device_handle *handle; | ||
750 | usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address); | ||
751 | // No blocking operation can follow: it may be run in the libusb hotplug callback and libusb will refuse any | ||
752 | // blocking call | ||
753 | if((res = libusb_open(dev, &handle)) != 0) { | ||
754 | usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %s", bus, address, libusb_error_name(res)); | ||
755 | return -1; | ||
756 | } | ||
757 | |||
758 | // Add the created handle to the device list, so we can close it in case of failure/disconnection | ||
759 | usbdev = malloc(sizeof(struct usb_device)); | ||
760 | memset(usbdev, 0, sizeof(*usbdev)); | ||
761 | |||
762 | usbdev->serial[0] = 0; | ||
763 | usbdev->bus = bus; | ||
764 | usbdev->address = address; | ||
765 | usbdev->devdesc = devdesc; | ||
766 | usbdev->speed = 0; | ||
767 | usbdev->handle = handle; | ||
768 | usbdev->alive = 1; | ||
769 | |||
770 | collection_init(&usbdev->tx_xfers); | ||
771 | collection_init(&usbdev->rx_xfers); | ||
772 | |||
773 | collection_add(&device_list, usbdev); | ||
774 | |||
775 | // On top of configurations, Apple have multiple "modes" for devices, namely: | ||
776 | // 1: An "initial" mode with 4 configurations | ||
777 | // 2: "Valeria" mode, where configuration 5 is included with interface for H.265 video capture (activated when recording screen with QuickTime in macOS) | ||
778 | // 3: "CDC NCM" mode, where configuration 5 is included with interface for Ethernet/USB (activated using internet-sharing feature in macOS) | ||
779 | // Request current mode asynchroniously, so it can be changed in callback if needed | ||
780 | usbmuxd_log(LL_INFO, "Requesting current mode from device %i-%i", bus, address); | ||
781 | struct mode_context* context = malloc(sizeof(struct mode_context)); | ||
782 | context->dev = dev; | ||
783 | context->bus = bus; | ||
784 | context->address = address; | ||
785 | context->bRequest = APPLE_VEND_SPECIFIC_GET_MODE; | ||
786 | context->wValue = 0; | ||
787 | context->wIndex = 0; | ||
788 | context->wLength = 4; | ||
789 | context->timeout = 1000; | ||
790 | |||
791 | if(submit_vendor_specific(handle, context, get_mode_cb) != 0) { | ||
792 | usbmuxd_log(LL_WARNING, "Could not request current mode from device %d-%d", bus, address); | ||
793 | // Schedule device for close and cleanup | ||
794 | usbdev->alive = 0; | ||
795 | return -1; | ||
796 | } | ||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | int usb_discover(void) | ||
801 | { | ||
802 | int cnt, i; | ||
803 | int valid_count = 0; | ||
804 | libusb_device **devs; | ||
805 | |||
806 | cnt = libusb_get_device_list(NULL, &devs); | ||
807 | if(cnt < 0) { | ||
808 | usbmuxd_log(LL_WARNING, "Could not get device list: %d", cnt); | ||
809 | devlist_failures++; | ||
810 | // sometimes libusb fails getting the device list if you've just removed something | ||
811 | if(devlist_failures > 5) { | ||
812 | usbmuxd_log(LL_FATAL, "Too many errors getting device list"); | ||
813 | return cnt; | ||
814 | } else { | ||
815 | get_tick_count(&next_dev_poll_time); | ||
816 | next_dev_poll_time.tv_usec += DEVICE_POLL_TIME * 1000; | ||
817 | next_dev_poll_time.tv_sec += next_dev_poll_time.tv_usec / 1000000; | ||
818 | next_dev_poll_time.tv_usec = next_dev_poll_time.tv_usec % 1000000; | ||
819 | return 0; | ||
820 | } | ||
821 | } | ||
822 | devlist_failures = 0; | ||
823 | |||
824 | usbmuxd_log(LL_SPEW, "usb_discover: scanning %d devices", cnt); | ||
825 | |||
826 | // Mark all devices as dead, and do a mark-sweep like | ||
827 | // collection of dead devices | ||
828 | FOREACH(struct usb_device *usbdev, &device_list) { | ||
829 | usbdev->alive = 0; | ||
830 | } ENDFOREACH | ||
831 | |||
832 | // Enumerate all USB devices and mark the ones we already know | ||
833 | // about as live, again | ||
834 | for(i=0; i<cnt; i++) { | ||
835 | libusb_device *dev = devs[i]; | ||
836 | if (usb_device_add(dev) < 0) { | ||
837 | continue; | ||
838 | } | ||
839 | valid_count++; | ||
840 | } | ||
841 | |||
842 | // Clean out any device we didn't mark back as live | ||
843 | reap_dead_devices(); | ||
844 | |||
845 | libusb_free_device_list(devs, 1); | ||
846 | |||
847 | get_tick_count(&next_dev_poll_time); | ||
848 | next_dev_poll_time.tv_usec += DEVICE_POLL_TIME * 1000; | ||
849 | next_dev_poll_time.tv_sec += next_dev_poll_time.tv_usec / 1000000; | ||
850 | next_dev_poll_time.tv_usec = next_dev_poll_time.tv_usec % 1000000; | ||
851 | |||
852 | return valid_count; | ||
853 | } | ||
854 | |||
855 | const char *usb_get_serial(struct usb_device *dev) | ||
856 | { | ||
857 | if(!dev->handle) { | ||
858 | return NULL; | ||
859 | } | ||
860 | return dev->serial; | ||
861 | } | ||
862 | |||
863 | uint32_t usb_get_location(struct usb_device *dev) | ||
864 | { | ||
865 | if(!dev->handle) { | ||
866 | return 0; | ||
867 | } | ||
868 | return (dev->bus << 16) | dev->address; | ||
869 | } | ||
870 | |||
871 | uint16_t usb_get_pid(struct usb_device *dev) | ||
872 | { | ||
873 | if(!dev->handle) { | ||
874 | return 0; | ||
875 | } | ||
876 | return dev->devdesc.idProduct; | ||
877 | } | ||
878 | |||
879 | uint64_t usb_get_speed(struct usb_device *dev) | ||
880 | { | ||
881 | if (!dev->handle) { | ||
882 | return 0; | ||
883 | } | ||
884 | return dev->speed; | ||
885 | } | ||
886 | |||
887 | void usb_get_fds(struct fdlist *list) | ||
888 | { | ||
889 | const struct libusb_pollfd **usbfds; | ||
890 | const struct libusb_pollfd **p; | ||
891 | usbfds = libusb_get_pollfds(NULL); | ||
892 | if(!usbfds) { | ||
893 | usbmuxd_log(LL_ERROR, "libusb_get_pollfds failed"); | ||
894 | return; | ||
895 | } | ||
896 | p = usbfds; | ||
897 | while(*p) { | ||
898 | fdlist_add(list, FD_USB, (*p)->fd, (*p)->events); | ||
899 | p++; | ||
900 | } | ||
901 | free(usbfds); | ||
902 | } | ||
903 | |||
904 | void usb_autodiscover(int enable) | ||
905 | { | ||
906 | usbmuxd_log(LL_DEBUG, "usb polling enable: %d", enable); | ||
907 | device_polling = enable; | ||
908 | device_hotplug = enable; | ||
909 | } | ||
910 | |||
911 | static int dev_poll_remain_ms(void) | ||
912 | { | ||
913 | int msecs; | ||
914 | struct timeval tv; | ||
915 | if(!device_polling) | ||
916 | return 100000; // devices will never be polled if this is > 0 | ||
917 | get_tick_count(&tv); | ||
918 | msecs = (next_dev_poll_time.tv_sec - tv.tv_sec) * 1000; | ||
919 | msecs += (next_dev_poll_time.tv_usec - tv.tv_usec) / 1000; | ||
920 | if(msecs < 0) | ||
921 | return 0; | ||
922 | return msecs; | ||
923 | } | ||
924 | |||
925 | int usb_get_timeout(void) | ||
926 | { | ||
927 | struct timeval tv; | ||
928 | int msec; | ||
929 | int res; | ||
930 | int pollrem; | ||
931 | pollrem = dev_poll_remain_ms(); | ||
932 | res = libusb_get_next_timeout(NULL, &tv); | ||
933 | if(res == 0) | ||
934 | return pollrem; | ||
935 | if(res < 0) { | ||
936 | usbmuxd_log(LL_ERROR, "libusb_get_next_timeout failed: %s", libusb_error_name(res)); | ||
937 | return pollrem; | ||
938 | } | ||
939 | msec = tv.tv_sec * 1000; | ||
940 | msec += tv.tv_usec / 1000; | ||
941 | if(msec > pollrem) | ||
942 | return pollrem; | ||
943 | return msec; | ||
944 | } | ||
945 | |||
946 | int usb_process(void) | ||
947 | { | ||
948 | int res; | ||
949 | struct timeval tv; | ||
950 | tv.tv_sec = tv.tv_usec = 0; | ||
951 | res = libusb_handle_events_timeout(NULL, &tv); | ||
952 | if(res < 0) { | ||
953 | usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %s", libusb_error_name(res)); | ||
954 | return res; | ||
955 | } | ||
956 | |||
957 | // reap devices marked dead due to an RX error | ||
958 | reap_dead_devices(); | ||
959 | |||
960 | if(dev_poll_remain_ms() <= 0) { | ||
961 | res = usb_discover(); | ||
962 | if(res < 0) { | ||
963 | usbmuxd_log(LL_ERROR, "usb_discover failed: %s", libusb_error_name(res)); | ||
964 | return res; | ||
965 | } | ||
966 | } | ||
967 | return 0; | ||
968 | } | ||
969 | |||
970 | int usb_process_timeout(int msec) | ||
971 | { | ||
972 | int res; | ||
973 | struct timeval tleft, tcur, tfin; | ||
974 | get_tick_count(&tcur); | ||
975 | tfin.tv_sec = tcur.tv_sec + (msec / 1000); | ||
976 | tfin.tv_usec = tcur.tv_usec + (msec % 1000) * 1000; | ||
977 | tfin.tv_sec += tfin.tv_usec / 1000000; | ||
978 | tfin.tv_usec %= 1000000; | ||
979 | while((tfin.tv_sec > tcur.tv_sec) || ((tfin.tv_sec == tcur.tv_sec) && (tfin.tv_usec > tcur.tv_usec))) { | ||
980 | tleft.tv_sec = tfin.tv_sec - tcur.tv_sec; | ||
981 | tleft.tv_usec = tfin.tv_usec - tcur.tv_usec; | ||
982 | if(tleft.tv_usec < 0) { | ||
983 | tleft.tv_usec += 1000000; | ||
984 | tleft.tv_sec -= 1; | ||
985 | } | ||
986 | res = libusb_handle_events_timeout(NULL, &tleft); | ||
987 | if(res < 0) { | ||
988 | usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %s", libusb_error_name(res)); | ||
989 | return res; | ||
990 | } | ||
991 | // reap devices marked dead due to an RX error | ||
992 | reap_dead_devices(); | ||
993 | get_tick_count(&tcur); | ||
994 | } | ||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | #ifdef HAVE_LIBUSB_HOTPLUG_API | ||
999 | static libusb_hotplug_callback_handle usb_hotplug_cb_handle; | ||
1000 | |||
1001 | static int usb_hotplug_cb(libusb_context *ctx, libusb_device *device, libusb_hotplug_event event, void *user_data) | ||
1002 | { | ||
1003 | if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == event) { | ||
1004 | if (device_hotplug) { | ||
1005 | usb_device_add(device); | ||
1006 | } | ||
1007 | } else if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) { | ||
1008 | uint8_t bus = libusb_get_bus_number(device); | ||
1009 | uint8_t address = libusb_get_device_address(device); | ||
1010 | FOREACH(struct usb_device *usbdev, &device_list) { | ||
1011 | if(usbdev->bus == bus && usbdev->address == address) { | ||
1012 | usbdev->alive = 0; | ||
1013 | device_remove(usbdev); | ||
1014 | break; | ||
1015 | } | ||
1016 | } ENDFOREACH | ||
1017 | } else { | ||
1018 | usbmuxd_log(LL_ERROR, "Unhandled event %d", event); | ||
1019 | } | ||
1020 | return 0; | ||
1021 | } | ||
1022 | #endif | ||
1023 | |||
1024 | int usb_init(void) | ||
1025 | { | ||
1026 | int res; | ||
1027 | const struct libusb_version* libusb_version_info = libusb_get_version(); | ||
1028 | usbmuxd_log(LL_NOTICE, "Using libusb %d.%d.%d", libusb_version_info->major, libusb_version_info->minor, libusb_version_info->micro); | ||
1029 | |||
1030 | devlist_failures = 0; | ||
1031 | device_polling = 1; | ||
1032 | res = libusb_init(NULL); | ||
1033 | |||
1034 | if (res != 0) { | ||
1035 | usbmuxd_log(LL_FATAL, "libusb_init failed: %s", libusb_error_name(res)); | ||
1036 | return -1; | ||
1037 | } | ||
1038 | |||
1039 | #if LIBUSB_API_VERSION >= 0x01000106 | ||
1040 | libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, (log_level >= LL_DEBUG ? LIBUSB_LOG_LEVEL_DEBUG: (log_level >= LL_WARNING ? LIBUSB_LOG_LEVEL_WARNING: LIBUSB_LOG_LEVEL_NONE))); | ||
1041 | #else | ||
1042 | libusb_set_debug(NULL, (log_level >= LL_DEBUG ? LIBUSB_LOG_LEVEL_DEBUG: (log_level >= LL_WARNING ? LIBUSB_LOG_LEVEL_WARNING: LIBUSB_LOG_LEVEL_NONE))); | ||
1043 | #endif | ||
1044 | |||
1045 | collection_init(&device_list); | ||
1046 | |||
1047 | #ifdef HAVE_LIBUSB_HOTPLUG_API | ||
1048 | if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { | ||
1049 | usbmuxd_log(LL_INFO, "Registering for libusb hotplug events"); | ||
1050 | 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); | ||
1051 | if (res == LIBUSB_SUCCESS) { | ||
1052 | device_polling = 0; | ||
1053 | } else { | ||
1054 | usbmuxd_log(LL_ERROR, "ERROR: Could not register for libusb hotplug events. %s", libusb_error_name(res)); | ||
1055 | } | ||
1056 | } else { | ||
1057 | usbmuxd_log(LL_ERROR, "libusb does not support hotplug events"); | ||
1058 | } | ||
1059 | #endif | ||
1060 | if (device_polling) { | ||
1061 | res = usb_discover(); | ||
1062 | if (res >= 0) { | ||
1063 | } | ||
1064 | } else { | ||
1065 | res = collection_count(&device_list); | ||
1066 | } | ||
1067 | return res; | ||
1068 | } | ||
1069 | |||
1070 | void usb_shutdown(void) | ||
1071 | { | ||
1072 | usbmuxd_log(LL_DEBUG, "usb_shutdown"); | ||
1073 | |||
1074 | #ifdef HAVE_LIBUSB_HOTPLUG_API | ||
1075 | libusb_hotplug_deregister_callback(NULL, usb_hotplug_cb_handle); | ||
1076 | #endif | ||
1077 | |||
1078 | FOREACH(struct usb_device *usbdev, &device_list) { | ||
1079 | device_remove(usbdev); | ||
1080 | usb_disconnect(usbdev); | ||
1081 | } ENDFOREACH | ||
1082 | collection_free(&device_list); | ||
1083 | libusb_exit(NULL); | ||
1084 | } | ||