summaryrefslogtreecommitdiffstats
path: root/daemon/usb-linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/usb-linux.c')
-rw-r--r--daemon/usb-linux.c589
1 files changed, 0 insertions, 589 deletions
diff --git a/daemon/usb-linux.c b/daemon/usb-linux.c
deleted file mode 100644
index 0860b46..0000000
--- a/daemon/usb-linux.c
+++ /dev/null
@@ -1,589 +0,0 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
5Copyright (C) 2009 Nikias Bassen <nikias@gmx.li>
6Copyright (C) 2009 Martin Szulecki <opensuse@sukimashita.com>
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 2 or version 3.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, write to the Free Software
19Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
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 "usb.h"
35#include "log.h"
36#include "device.h"
37
38// interval for device connection/disconnection polling, in milliseconds
39// we need this because there is currently no asynchronous device discovery mechanism in libusb
40#define DEVICE_POLL_TIME 1000
41
42struct usb_device {
43 libusb_device_handle *dev;
44 uint8_t bus, address;
45 uint16_t vid, pid;
46 char serial[256];
47 int alive;
48 uint8_t interface, ep_in, ep_out;
49 struct libusb_transfer *rx_xfer;
50 struct collection tx_xfers;
51 int wMaxPacketSize;
52};
53
54static struct collection device_list;
55
56static struct timeval next_dev_poll_time;
57
58static int devlist_failures;
59static int device_polling;
60
61static void usb_disconnect(struct usb_device *dev)
62{
63 if(!dev->dev) {
64 return;
65 }
66
67 // kill the rx xfer and tx xfers and try to make sure the callbacks get called before we free the device
68 if(dev->rx_xfer) {
69 usbmuxd_log(LL_DEBUG, "usb_disconnect: cancelling RX xfer");
70 libusb_cancel_transfer(dev->rx_xfer);
71 }
72 FOREACH(struct libusb_transfer *xfer, &dev->tx_xfers) {
73 usbmuxd_log(LL_DEBUG, "usb_disconnect: cancelling TX xfer %p", xfer);
74 libusb_cancel_transfer(xfer);
75 } ENDFOREACH
76
77 while(dev->rx_xfer || collection_count(&dev->tx_xfers)) {
78 struct timeval tv;
79 int res;
80
81 tv.tv_sec = 0;
82 tv.tv_usec = 1000;
83 if((res = libusb_handle_events_timeout(NULL, &tv)) < 0) {
84 usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout for usb_disconnect failed: %d", res);
85 break;
86 }
87 }
88 collection_free(&dev->tx_xfers);
89 libusb_release_interface(dev->dev, dev->interface);
90 libusb_close(dev->dev);
91 dev->dev = NULL;
92 collection_remove(&device_list, dev);
93 free(dev);
94}
95
96static void tx_callback(struct libusb_transfer *xfer)
97{
98 struct usb_device *dev = xfer->user_data;
99 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);
100 if(xfer->status != LIBUSB_TRANSFER_COMPLETED) {
101 switch(xfer->status) {
102 case LIBUSB_TRANSFER_COMPLETED: //shut up compiler
103 case LIBUSB_TRANSFER_ERROR:
104 // funny, this happens when we disconnect the device while waiting for a transfer, sometimes
105 usbmuxd_log(LL_INFO, "Device %d-%d TX aborted due to error or disconnect", dev->bus, dev->address);
106 break;
107 case LIBUSB_TRANSFER_TIMED_OUT:
108 usbmuxd_log(LL_ERROR, "TX transfer timed out for device %d-%d", dev->bus, dev->address);
109 break;
110 case LIBUSB_TRANSFER_CANCELLED:
111 usbmuxd_log(LL_DEBUG, "Device %d-%d TX transfer cancelled", dev->bus, dev->address);
112 break;
113 case LIBUSB_TRANSFER_STALL:
114 usbmuxd_log(LL_ERROR, "TX transfer stalled for device %d-%d", dev->bus, dev->address);
115 break;
116 case LIBUSB_TRANSFER_NO_DEVICE:
117 // other times, this happens, and also even when we abort the transfer after device removal
118 usbmuxd_log(LL_INFO, "Device %d-%d TX aborted due to disconnect", dev->bus, dev->address);
119 break;
120 case LIBUSB_TRANSFER_OVERFLOW:
121 usbmuxd_log(LL_ERROR, "TX transfer overflow for device %d-%d", dev->bus, dev->address);
122 break;
123 // and nothing happens (this never gets called) if the device is freed after a disconnect! (bad)
124 }
125 // we can't usb_disconnect here due to a deadlock, so instead mark it as dead and reap it after processing events
126 // we'll do device_remove there too
127 dev->alive = 0;
128 }
129 if(xfer->buffer)
130 free(xfer->buffer);
131 collection_remove(&dev->tx_xfers, xfer);
132 libusb_free_transfer(xfer);
133}
134
135int usb_send(struct usb_device *dev, const unsigned char *buf, int length)
136{
137 int res;
138 struct libusb_transfer *xfer = libusb_alloc_transfer(0);
139 libusb_fill_bulk_transfer(xfer, dev->dev, dev->ep_out, (void*)buf, length, tx_callback, dev, 0);
140 if((res = libusb_submit_transfer(xfer)) < 0) {
141 usbmuxd_log(LL_ERROR, "Failed to submit TX transfer %p len %d to device %d-%d: %d", buf, length, dev->bus, dev->address, res);
142 libusb_free_transfer(xfer);
143 return res;
144 }
145 collection_add(&dev->tx_xfers, xfer);
146 if (length % dev->wMaxPacketSize == 0) {
147 usbmuxd_log(LL_DEBUG, "Send ZLP");
148 // Send Zero Length Packet
149 xfer = libusb_alloc_transfer(0);
150 void *buffer = malloc(1);
151 libusb_fill_bulk_transfer(xfer, dev->dev, dev->ep_out, buffer, 0, tx_callback, dev, 0);
152 if((res = libusb_submit_transfer(xfer)) < 0) {
153 usbmuxd_log(LL_ERROR, "Failed to submit TX ZLP transfer to device %d-%d: %d", dev->bus, dev->address, res);
154 libusb_free_transfer(xfer);
155 return res;
156 }
157 collection_add(&dev->tx_xfers, xfer);
158 }
159 return 0;
160}
161
162static void rx_callback(struct libusb_transfer *xfer)
163{
164 struct usb_device *dev = xfer->user_data;
165 usbmuxd_log(LL_SPEW, "RX callback dev %d-%d len %d status %d", dev->bus, dev->address, xfer->actual_length, xfer->status);
166 if(xfer->status == LIBUSB_TRANSFER_COMPLETED) {
167 device_data_input(dev, xfer->buffer, xfer->actual_length);
168 libusb_submit_transfer(xfer);
169 } else {
170 switch(xfer->status) {
171 case LIBUSB_TRANSFER_COMPLETED: //shut up compiler
172 case LIBUSB_TRANSFER_ERROR:
173 // funny, this happens when we disconnect the device while waiting for a transfer, sometimes
174 usbmuxd_log(LL_INFO, "Device %d-%d RX aborted due to error or disconnect", dev->bus, dev->address);
175 break;
176 case LIBUSB_TRANSFER_TIMED_OUT:
177 usbmuxd_log(LL_ERROR, "RX transfer timed out for device %d-%d", dev->bus, dev->address);
178 break;
179 case LIBUSB_TRANSFER_CANCELLED:
180 usbmuxd_log(LL_DEBUG, "Device %d-%d RX transfer cancelled", dev->bus, dev->address);
181 break;
182 case LIBUSB_TRANSFER_STALL:
183 usbmuxd_log(LL_ERROR, "RX transfer stalled for device %d-%d", dev->bus, dev->address);
184 break;
185 case LIBUSB_TRANSFER_NO_DEVICE:
186 // other times, this happens, and also even when we abort the transfer after device removal
187 usbmuxd_log(LL_INFO, "Device %d-%d RX aborted due to disconnect", dev->bus, dev->address);
188 break;
189 case LIBUSB_TRANSFER_OVERFLOW:
190 usbmuxd_log(LL_ERROR, "RX transfer overflow for device %d-%d", dev->bus, dev->address);
191 break;
192 // and nothing happens (this never gets called) if the device is freed after a disconnect! (bad)
193 }
194 free(xfer->buffer);
195 dev->rx_xfer = NULL;
196 libusb_free_transfer(xfer);
197 // we can't usb_disconnect here due to a deadlock, so instead mark it as dead and reap it after processing events
198 // we'll do device_remove there too
199 dev->alive = 0;
200 }
201}
202
203static int start_rx(struct usb_device *dev)
204{
205 int res;
206 void *buf;
207 dev->rx_xfer = libusb_alloc_transfer(0);
208 buf = malloc(USB_MRU);
209 libusb_fill_bulk_transfer(dev->rx_xfer, dev->dev, dev->ep_in, buf, USB_MRU, rx_callback, dev, 0);
210 if((res = libusb_submit_transfer(dev->rx_xfer)) != 0) {
211 usbmuxd_log(LL_ERROR, "Failed to submit RX transfer to device %d-%d: %d", dev->bus, dev->address, res);
212 libusb_free_transfer(dev->rx_xfer);
213 dev->rx_xfer = NULL;
214 return res;
215 }
216 return 0;
217}
218
219int usb_discover(void)
220{
221 int cnt, i, j, res;
222 int valid_count = 0;
223 libusb_device **devs;
224
225 cnt = libusb_get_device_list(NULL, &devs);
226 if(cnt < 0) {
227 usbmuxd_log(LL_WARNING, "Could not get device list: %d", cnt);
228 devlist_failures++;
229 // sometimes libusb fails getting the device list if you've just removed something
230 if(devlist_failures > 5) {
231 usbmuxd_log(LL_FATAL, "Too many errors getting device list\n");
232 return cnt;
233 } else {
234 gettimeofday(&next_dev_poll_time, NULL);
235 next_dev_poll_time.tv_usec += DEVICE_POLL_TIME * 1000;
236 next_dev_poll_time.tv_sec += next_dev_poll_time.tv_usec / 1000000;
237 next_dev_poll_time.tv_usec = next_dev_poll_time.tv_usec % 1000000;
238 return 0;
239 }
240 }
241 devlist_failures = 0;
242
243 usbmuxd_log(LL_SPEW, "usb_discover: scanning %d devices", cnt);
244
245 FOREACH(struct usb_device *usbdev, &device_list) {
246 usbdev->alive = 0;
247 } ENDFOREACH
248
249 for(i=0; i<cnt; i++) {
250 // the following are non-blocking operations on the device list
251 libusb_device *dev = devs[i];
252 uint8_t bus = libusb_get_bus_number(dev);
253 uint8_t address = libusb_get_device_address(dev);
254 struct libusb_device_descriptor devdesc;
255 int found = 0;
256 FOREACH(struct usb_device *usbdev, &device_list) {
257 if(usbdev->bus == bus && usbdev->address == address) {
258 valid_count++;
259 usbdev->alive = 1;
260 found = 1;
261 break;
262 }
263 } ENDFOREACH
264 if(found)
265 continue; //device already found
266 if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) {
267 usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %d", bus, address, res);
268 continue;
269 }
270 if(devdesc.idVendor != VID_APPLE)
271 continue;
272 if((devdesc.idProduct < PID_RANGE_LOW) ||
273 (devdesc.idProduct > PID_RANGE_MAX))
274 continue;
275 libusb_device_handle *handle;
276 usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address);
277 // potentially blocking operations follow; they will only run when new devices are detected, which is acceptable
278 if((res = libusb_open(dev, &handle)) != 0) {
279 usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %d", bus, address, res);
280 continue;
281 }
282 int current_config = 0;
283 if((res = libusb_get_configuration(handle, &current_config)) != 0) {
284 usbmuxd_log(LL_WARNING, "Could not get configuration for device %d-%d: %d", bus, address, res);
285 libusb_close(handle);
286 continue;
287 }
288 if (current_config != devdesc.bNumConfigurations) {
289 struct libusb_config_descriptor *config;
290 if((res = libusb_get_active_config_descriptor(dev, &config)) != 0) {
291 usbmuxd_log(LL_NOTICE, "Could not get old configuration descriptor for device %d-%d: %d", bus, address, res);
292 } else {
293 for(j=0; j<config->bNumInterfaces; j++) {
294 const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0];
295 if((res = libusb_kernel_driver_active(handle, intf->bInterfaceNumber)) < 0) {
296 usbmuxd_log(LL_NOTICE, "Could not check kernel ownership of interface %d for device %d-%d: %d", intf->bInterfaceNumber, bus, address, res);
297 continue;
298 }
299 if(res == 1) {
300 usbmuxd_log(LL_INFO, "Detaching kernel driver for device %d-%d, interface %d", bus, address, intf->bInterfaceNumber);
301 if((res = libusb_detach_kernel_driver(handle, intf->bInterfaceNumber)) < 0) {
302 usbmuxd_log(LL_WARNING, "Could not detach kernel driver (%d), configuration change will probably fail!", res);
303 continue;
304 }
305 }
306 }
307 libusb_free_config_descriptor(config);
308 }
309 if((res = libusb_set_configuration(handle, devdesc.bNumConfigurations)) != 0) {
310 usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %d", devdesc.bNumConfigurations, bus, address, res);
311 libusb_close(handle);
312 continue;
313 }
314 }
315
316 struct libusb_config_descriptor *config;
317 if((res = libusb_get_active_config_descriptor(dev, &config)) != 0) {
318 usbmuxd_log(LL_WARNING, "Could not get configuration descriptor for device %d-%d: %d", bus, address, res);
319 libusb_close(handle);
320 continue;
321 }
322
323 struct usb_device *usbdev;
324 usbdev = malloc(sizeof(struct usb_device));
325 memset(usbdev, 0, sizeof(*usbdev));
326
327 for(j=0; j<config->bNumInterfaces; j++) {
328 const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0];
329 if(intf->bInterfaceClass != INTERFACE_CLASS ||
330 intf->bInterfaceSubClass != INTERFACE_SUBCLASS ||
331 intf->bInterfaceProtocol != INTERFACE_PROTOCOL)
332 continue;
333 if(intf->bNumEndpoints != 2) {
334 usbmuxd_log(LL_WARNING, "Endpoint count mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address);
335 continue;
336 }
337 if((intf->endpoint[0].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_OUT ||
338 (intf->endpoint[1].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_IN) {
339 usbmuxd_log(LL_WARNING, "Endpoint type mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address);
340 continue;
341 }
342 usbdev->interface = intf->bInterfaceNumber;
343 usbdev->ep_out = intf->endpoint[0].bEndpointAddress;
344 usbdev->ep_in = intf->endpoint[1].bEndpointAddress;
345 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);
346 break;
347 }
348 libusb_free_config_descriptor(config);
349
350 if(j == config->bNumInterfaces) {
351 usbmuxd_log(LL_WARNING, "Could not find a suitable USB interface for device %d-%d", bus, address);
352 libusb_close(handle);
353 free(usbdev);
354 continue;
355 }
356
357 if((res = libusb_claim_interface(handle, usbdev->interface)) != 0) {
358 usbmuxd_log(LL_WARNING, "Could not claim interface %d for device %d-%d: %d", usbdev->interface, bus, address, res);
359 libusb_close(handle);
360 free(usbdev);
361 continue;
362 }
363
364 if((res = libusb_get_string_descriptor_ascii(handle, devdesc.iSerialNumber, (uint8_t *)usbdev->serial, 256)) <= 0) {
365 usbmuxd_log(LL_WARNING, "Could not get serial number for device %d-%d: %d", bus, address, res);
366 libusb_release_interface(handle, usbdev->interface);
367 libusb_close(handle);
368 free(usbdev);
369 continue;
370 }
371 usbdev->serial[res] = 0;
372 usbdev->bus = bus;
373 usbdev->address = address;
374 usbdev->vid = devdesc.idVendor;
375 usbdev->pid = devdesc.idProduct;
376 usbdev->dev = handle;
377 usbdev->alive = 1;
378 usbdev->wMaxPacketSize = libusb_get_max_packet_size(dev, usbdev->ep_out);
379 if (usbdev->wMaxPacketSize <= 0) {
380 usbmuxd_log(LL_ERROR, "Could not determine wMaxPacketSize for device %d-%d, setting to 64", usbdev->bus, usbdev->address);
381 usbdev->wMaxPacketSize = 64;
382 } else {
383 usbmuxd_log(LL_INFO, "Using wMaxPacketSize=%d for device %d-%d", usbdev->wMaxPacketSize, usbdev->bus, usbdev->address);
384 }
385
386 collection_init(&usbdev->tx_xfers);
387
388 collection_add(&device_list, usbdev);
389
390 if(device_add(usbdev) < 0) {
391 usb_disconnect(usbdev);
392 continue;
393 }
394 if(start_rx(usbdev) < 0) {
395 device_remove(usbdev);
396 usb_disconnect(usbdev);
397 continue;
398 }
399 valid_count++;
400 }
401 FOREACH(struct usb_device *usbdev, &device_list) {
402 if(!usbdev->alive) {
403 device_remove(usbdev);
404 usb_disconnect(usbdev);
405 }
406 } ENDFOREACH
407
408 libusb_free_device_list(devs, 1);
409
410 gettimeofday(&next_dev_poll_time, NULL);
411 next_dev_poll_time.tv_usec += DEVICE_POLL_TIME * 1000;
412 next_dev_poll_time.tv_sec += next_dev_poll_time.tv_usec / 1000000;
413 next_dev_poll_time.tv_usec = next_dev_poll_time.tv_usec % 1000000;
414
415 return valid_count;
416}
417
418const char *usb_get_serial(struct usb_device *dev)
419{
420 if(!dev->dev) {
421 return NULL;
422 }
423 return dev->serial;
424}
425
426uint32_t usb_get_location(struct usb_device *dev)
427{
428 if(!dev->dev) {
429 return 0;
430 }
431 return (dev->bus << 16) | dev->address;
432}
433
434uint16_t usb_get_pid(struct usb_device *dev)
435{
436 if(!dev->dev) {
437 return 0;
438 }
439 return dev->pid;
440}
441
442void usb_get_fds(struct fdlist *list)
443{
444 const struct libusb_pollfd **usbfds;
445 const struct libusb_pollfd **p;
446 usbfds = libusb_get_pollfds(NULL);
447 if(!usbfds) {
448 usbmuxd_log(LL_ERROR, "libusb_get_pollfds failed");
449 return;
450 }
451 p = usbfds;
452 while(*p) {
453 fdlist_add(list, FD_USB, (*p)->fd, (*p)->events);
454 p++;
455 }
456 free(usbfds);
457}
458
459void usb_autodiscover(int enable)
460{
461 usbmuxd_log(LL_DEBUG, "usb polling enable: %d", enable);
462 device_polling = enable;
463}
464
465static int dev_poll_remain_ms(void)
466{
467 int msecs;
468 struct timeval tv;
469 if(!device_polling)
470 return 100000; // devices will never be polled if this is > 0
471 gettimeofday(&tv, NULL);
472 msecs = (next_dev_poll_time.tv_sec - tv.tv_sec) * 1000;
473 msecs += (next_dev_poll_time.tv_usec - tv.tv_usec) / 1000;
474 if(msecs < 0)
475 return 0;
476 return msecs;
477}
478
479int usb_get_timeout(void)
480{
481 struct timeval tv;
482 int msec;
483 int res;
484 int pollrem;
485 pollrem = dev_poll_remain_ms();
486 res = libusb_get_next_timeout(NULL, &tv);
487 if(res == 0)
488 return pollrem;
489 if(res < 0) {
490 usbmuxd_log(LL_ERROR, "libusb_get_next_timeout failed: %d", res);
491 return pollrem;
492 }
493 msec = tv.tv_sec * 1000;
494 msec += tv.tv_usec / 1000;
495 if(msec > pollrem)
496 return pollrem;
497 return msec;
498}
499
500int usb_process(void)
501{
502 int res;
503 struct timeval tv;
504 tv.tv_sec = tv.tv_usec = 0;
505 res = libusb_handle_events_timeout(NULL, &tv);
506 if(res < 0) {
507 usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %d", res);
508 return res;
509 }
510 // reap devices marked dead due to an RX error
511 FOREACH(struct usb_device *usbdev, &device_list) {
512 if(!usbdev->alive) {
513 device_remove(usbdev);
514 usb_disconnect(usbdev);
515 }
516 } ENDFOREACH
517
518 if(dev_poll_remain_ms() <= 0) {
519 res = usb_discover();
520 if(res < 0) {
521 usbmuxd_log(LL_ERROR, "usb_discover failed: %d", res);
522 return res;
523 }
524 }
525 return 0;
526}
527
528int usb_process_timeout(int msec)
529{
530 int res;
531 struct timeval tleft, tcur, tfin;
532 gettimeofday(&tcur, NULL);
533 tfin.tv_sec = tcur.tv_sec + (msec / 1000);
534 tfin.tv_usec = tcur.tv_usec + (msec % 1000) * 1000;
535 tfin.tv_sec += tfin.tv_usec / 1000000;
536 tfin.tv_usec %= 1000000;
537 while((tfin.tv_sec > tcur.tv_sec) || ((tfin.tv_sec == tcur.tv_sec) && (tfin.tv_usec > tcur.tv_usec))) {
538 tleft.tv_sec = tfin.tv_sec - tcur.tv_sec;
539 tleft.tv_usec = tfin.tv_usec - tcur.tv_usec;
540 if(tleft.tv_usec < 0) {
541 tleft.tv_usec += 1000000;
542 tleft.tv_sec -= 1;
543 }
544 res = libusb_handle_events_timeout(NULL, &tleft);
545 if(res < 0) {
546 usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %d", res);
547 return res;
548 }
549 // reap devices marked dead due to an RX error
550 FOREACH(struct usb_device *usbdev, &device_list) {
551 if(!usbdev->alive) {
552 device_remove(usbdev);
553 usb_disconnect(usbdev);
554 }
555 } ENDFOREACH
556 gettimeofday(&tcur, NULL);
557 }
558 return 0;
559}
560
561int usb_init(void)
562{
563 int res;
564 usbmuxd_log(LL_DEBUG, "usb_init for linux / libusb 1.0");
565
566 devlist_failures = 0;
567 device_polling = 1;
568 res = libusb_init(NULL);
569 //libusb_set_debug(NULL, 3);
570 if(res != 0) {
571 usbmuxd_log(LL_FATAL, "libusb_init failed: %d", res);
572 return -1;
573 }
574
575 collection_init(&device_list);
576
577 return usb_discover();
578}
579
580void usb_shutdown(void)
581{
582 usbmuxd_log(LL_DEBUG, "usb_shutdown");
583 FOREACH(struct usb_device *usbdev, &device_list) {
584 device_remove(usbdev);
585 usb_disconnect(usbdev);
586 } ENDFOREACH
587 collection_free(&device_list);
588 libusb_exit(NULL);
589}