libusb 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/.gitignore +8 -0
  2. data/.travis.yml +10 -0
  3. data/.yardopts +6 -1
  4. data/Gemfile +16 -0
  5. data/{History.txt → History.md} +28 -16
  6. data/README.md +144 -0
  7. data/Rakefile +28 -24
  8. data/ext/extconf.rb +33 -0
  9. data/ext/libusbx-1.0.14/AUTHORS +50 -0
  10. data/ext/libusbx-1.0.14/COPYING +504 -0
  11. data/ext/libusbx-1.0.14/ChangeLog +139 -0
  12. data/ext/libusbx-1.0.14/INSTALL +234 -0
  13. data/ext/libusbx-1.0.14/Makefile.am +23 -0
  14. data/ext/libusbx-1.0.14/Makefile.in +803 -0
  15. data/ext/libusbx-1.0.14/NEWS +2 -0
  16. data/ext/libusbx-1.0.14/PORTING +94 -0
  17. data/ext/libusbx-1.0.14/README +28 -0
  18. data/ext/libusbx-1.0.14/THANKS +7 -0
  19. data/ext/libusbx-1.0.14/TODO +2 -0
  20. data/ext/libusbx-1.0.14/aclocal.m4 +9480 -0
  21. data/ext/libusbx-1.0.14/compile +143 -0
  22. data/ext/libusbx-1.0.14/config.guess +1501 -0
  23. data/ext/libusbx-1.0.14/config.h.in +116 -0
  24. data/ext/libusbx-1.0.14/config.sub +1705 -0
  25. data/ext/libusbx-1.0.14/configure +14818 -0
  26. data/ext/libusbx-1.0.14/configure.ac +230 -0
  27. data/ext/libusbx-1.0.14/depcomp +630 -0
  28. data/ext/libusbx-1.0.14/doc/Makefile.am +9 -0
  29. data/ext/libusbx-1.0.14/doc/Makefile.in +380 -0
  30. data/ext/libusbx-1.0.14/doc/doxygen.cfg.in +1288 -0
  31. data/ext/libusbx-1.0.14/examples/Makefile.am +18 -0
  32. data/ext/libusbx-1.0.14/examples/Makefile.in +596 -0
  33. data/ext/libusbx-1.0.14/examples/dpfp.c +506 -0
  34. data/ext/libusbx-1.0.14/examples/dpfp_threaded.c +544 -0
  35. data/ext/libusbx-1.0.14/examples/ezusb.c +616 -0
  36. data/ext/libusbx-1.0.14/examples/ezusb.h +107 -0
  37. data/ext/libusbx-1.0.14/examples/fxload.c +261 -0
  38. data/ext/libusbx-1.0.14/examples/getopt/getopt.c +1060 -0
  39. data/ext/libusbx-1.0.14/examples/getopt/getopt.h +180 -0
  40. data/ext/libusbx-1.0.14/examples/getopt/getopt1.c +188 -0
  41. data/ext/libusbx-1.0.14/examples/listdevs.c +63 -0
  42. data/ext/libusbx-1.0.14/examples/xusb.c +1036 -0
  43. data/ext/libusbx-1.0.14/install-sh +520 -0
  44. data/ext/libusbx-1.0.14/libusb-1.0.pc.in +11 -0
  45. data/ext/libusbx-1.0.14/libusb/Makefile.am +56 -0
  46. data/ext/libusbx-1.0.14/libusb/Makefile.in +721 -0
  47. data/ext/libusbx-1.0.14/libusb/core.c +1951 -0
  48. data/ext/libusbx-1.0.14/libusb/descriptor.c +731 -0
  49. data/ext/libusbx-1.0.14/libusb/io.c +2450 -0
  50. data/ext/libusbx-1.0.14/libusb/libusb-1.0.def +126 -0
  51. data/ext/libusbx-1.0.14/libusb/libusb-1.0.rc +59 -0
  52. data/ext/libusbx-1.0.14/libusb/libusb.h +1506 -0
  53. data/ext/libusbx-1.0.14/libusb/libusbi.h +910 -0
  54. data/ext/libusbx-1.0.14/libusb/os/darwin_usb.c +1807 -0
  55. data/ext/libusbx-1.0.14/libusb/os/darwin_usb.h +169 -0
  56. data/ext/libusbx-1.0.14/libusb/os/linux_usbfs.c +2569 -0
  57. data/ext/libusbx-1.0.14/libusb/os/linux_usbfs.h +149 -0
  58. data/ext/libusbx-1.0.14/libusb/os/openbsd_usb.c +727 -0
  59. data/ext/libusbx-1.0.14/libusb/os/poll_posix.h +10 -0
  60. data/ext/libusbx-1.0.14/libusb/os/poll_windows.c +747 -0
  61. data/ext/libusbx-1.0.14/libusb/os/poll_windows.h +114 -0
  62. data/ext/libusbx-1.0.14/libusb/os/threads_posix.c +80 -0
  63. data/ext/libusbx-1.0.14/libusb/os/threads_posix.h +50 -0
  64. data/ext/libusbx-1.0.14/libusb/os/threads_windows.c +211 -0
  65. data/ext/libusbx-1.0.14/libusb/os/threads_windows.h +87 -0
  66. data/ext/libusbx-1.0.14/libusb/os/windows_usb.c +4369 -0
  67. data/ext/libusbx-1.0.14/libusb/os/windows_usb.h +979 -0
  68. data/ext/libusbx-1.0.14/libusb/sync.c +321 -0
  69. data/ext/libusbx-1.0.14/libusb/version.h +18 -0
  70. data/ext/libusbx-1.0.14/libusb/version_nano.h +1 -0
  71. data/ext/libusbx-1.0.14/ltmain.sh +9636 -0
  72. data/ext/libusbx-1.0.14/missing +376 -0
  73. data/lib/libusb.rb +2 -3
  74. data/lib/libusb/call.rb +49 -7
  75. data/lib/libusb/compat.rb +15 -9
  76. data/lib/libusb/configuration.rb +15 -3
  77. data/lib/libusb/constants.rb +19 -6
  78. data/lib/libusb/context.rb +181 -3
  79. data/lib/libusb/dev_handle.rb +91 -40
  80. data/lib/libusb/endpoint.rb +41 -14
  81. data/lib/libusb/eventmachine.rb +183 -0
  82. data/lib/libusb/transfer.rb +21 -8
  83. data/lib/libusb/version_gem.rb +19 -0
  84. data/lib/libusb/{version.rb → version_struct.rb} +0 -0
  85. data/libusb.gemspec +31 -0
  86. data/test/test_libusb_compat.rb +1 -1
  87. data/test/test_libusb_compat_mass_storage.rb +2 -2
  88. data/test/test_libusb_descriptors.rb +1 -1
  89. data/test/test_libusb_event_machine.rb +118 -0
  90. data/test/test_libusb_iso_transfer.rb +6 -1
  91. data/test/test_libusb_mass_storage.rb +9 -3
  92. data/test/test_libusb_mass_storage2.rb +1 -1
  93. data/test/test_libusb_structs.rb +45 -0
  94. data/test/test_libusb_threads.rb +89 -0
  95. data/test/test_libusb_version.rb +4 -0
  96. metadata +109 -44
  97. data/.autotest +0 -23
  98. data/.gemtest +0 -0
  99. data/Manifest.txt +0 -3
  100. data/README.rdoc +0 -115
  101. data/test/test_libusb_keyboard.rb +0 -50
@@ -0,0 +1,506 @@
1
+ /*
2
+ * libusbx example program to manipulate U.are.U 4000B fingerprint scanner.
3
+ * Copyright © 2007 Daniel Drake <dsd@gentoo.org>
4
+ *
5
+ * Basic image capture program only, does not consider the powerup quirks or
6
+ * the fact that image encryption may be enabled. Not expected to work
7
+ * flawlessly all of the time.
8
+ *
9
+ * This library is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU Lesser General Public
11
+ * License as published by the Free Software Foundation; either
12
+ * version 2.1 of the License, or (at your option) any later version.
13
+ *
14
+ * This library is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
+ * Lesser General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU Lesser General Public
20
+ * License along with this library; if not, write to the Free Software
21
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
+ */
23
+
24
+ #include <errno.h>
25
+ #include <signal.h>
26
+ #include <string.h>
27
+ #include <stdio.h>
28
+ #include <stdlib.h>
29
+
30
+ #include <libusb.h>
31
+
32
+ #define EP_INTR (1 | LIBUSB_ENDPOINT_IN)
33
+ #define EP_DATA (2 | LIBUSB_ENDPOINT_IN)
34
+ #define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)
35
+ #define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT)
36
+ #define USB_RQ 0x04
37
+ #define INTR_LENGTH 64
38
+
39
+ enum {
40
+ MODE_INIT = 0x00,
41
+ MODE_AWAIT_FINGER_ON = 0x10,
42
+ MODE_AWAIT_FINGER_OFF = 0x12,
43
+ MODE_CAPTURE = 0x20,
44
+ MODE_SHUT_UP = 0x30,
45
+ MODE_READY = 0x80,
46
+ };
47
+
48
+ static int next_state(void);
49
+
50
+ enum {
51
+ STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1,
52
+ STATE_AWAIT_IRQ_FINGER_DETECTED,
53
+ STATE_AWAIT_MODE_CHANGE_CAPTURE,
54
+ STATE_AWAIT_IMAGE,
55
+ STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF,
56
+ STATE_AWAIT_IRQ_FINGER_REMOVED,
57
+ };
58
+
59
+ static int state = 0;
60
+ static struct libusb_device_handle *devh = NULL;
61
+ static unsigned char imgbuf[0x1b340];
62
+ static unsigned char irqbuf[INTR_LENGTH];
63
+ static struct libusb_transfer *img_transfer = NULL;
64
+ static struct libusb_transfer *irq_transfer = NULL;
65
+ static int img_idx = 0;
66
+ static int do_exit = 0;
67
+
68
+ static int find_dpfp_device(void)
69
+ {
70
+ devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a);
71
+ return devh ? 0 : -EIO;
72
+ }
73
+
74
+ static int print_f0_data(void)
75
+ {
76
+ unsigned char data[0x10];
77
+ int r;
78
+ unsigned int i;
79
+
80
+ r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data,
81
+ sizeof(data), 0);
82
+ if (r < 0) {
83
+ fprintf(stderr, "F0 error %d\n", r);
84
+ return r;
85
+ }
86
+ if ((unsigned int) r < sizeof(data)) {
87
+ fprintf(stderr, "short read (%d)\n", r);
88
+ return -1;
89
+ }
90
+
91
+ printf("F0 data:");
92
+ for (i = 0; i < sizeof(data); i++)
93
+ printf("%02x ", data[i]);
94
+ printf("\n");
95
+ return 0;
96
+ }
97
+
98
+ static int get_hwstat(unsigned char *status)
99
+ {
100
+ int r;
101
+
102
+ r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0x07, 0, status, 1, 0);
103
+ if (r < 0) {
104
+ fprintf(stderr, "read hwstat error %d\n", r);
105
+ return r;
106
+ }
107
+ if ((unsigned int) r < 1) {
108
+ fprintf(stderr, "short read (%d)\n", r);
109
+ return -1;
110
+ }
111
+
112
+ printf("hwstat reads %02x\n", *status);
113
+ return 0;
114
+ }
115
+
116
+ static int set_hwstat(unsigned char data)
117
+ {
118
+ int r;
119
+
120
+ printf("set hwstat to %02x\n", data);
121
+ r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x07, 0, &data, 1, 0);
122
+ if (r < 0) {
123
+ fprintf(stderr, "set hwstat error %d\n", r);
124
+ return r;
125
+ }
126
+ if ((unsigned int) r < 1) {
127
+ fprintf(stderr, "short write (%d)", r);
128
+ return -1;
129
+ }
130
+
131
+ return 0;
132
+ }
133
+
134
+ static int set_mode(unsigned char data)
135
+ {
136
+ int r;
137
+ printf("set mode %02x\n", data);
138
+
139
+ r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0);
140
+ if (r < 0) {
141
+ fprintf(stderr, "set mode error %d\n", r);
142
+ return r;
143
+ }
144
+ if ((unsigned int) r < 1) {
145
+ fprintf(stderr, "short write (%d)", r);
146
+ return -1;
147
+ }
148
+
149
+ return 0;
150
+ }
151
+
152
+ static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer)
153
+ {
154
+ if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
155
+ fprintf(stderr, "mode change transfer not completed!\n");
156
+ do_exit = 2;
157
+ }
158
+
159
+ printf("async cb_mode_changed length=%d actual_length=%d\n",
160
+ transfer->length, transfer->actual_length);
161
+ if (next_state() < 0)
162
+ do_exit = 2;
163
+ }
164
+
165
+ static int set_mode_async(unsigned char data)
166
+ {
167
+ unsigned char *buf = (unsigned char*) malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
168
+ struct libusb_transfer *transfer;
169
+
170
+ if (!buf)
171
+ return -ENOMEM;
172
+
173
+ transfer = libusb_alloc_transfer(0);
174
+ if (!transfer) {
175
+ free(buf);
176
+ return -ENOMEM;
177
+ }
178
+
179
+ printf("async set mode %02x\n", data);
180
+ libusb_fill_control_setup(buf, CTRL_OUT, USB_RQ, 0x4e, 0, 1);
181
+ buf[LIBUSB_CONTROL_SETUP_SIZE] = data;
182
+ libusb_fill_control_transfer(transfer, devh, buf, cb_mode_changed, NULL,
183
+ 1000);
184
+
185
+ transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK
186
+ | LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
187
+ return libusb_submit_transfer(transfer);
188
+ }
189
+
190
+ static int do_sync_intr(unsigned char *data)
191
+ {
192
+ int r;
193
+ int transferred;
194
+
195
+ r = libusb_interrupt_transfer(devh, EP_INTR, data, INTR_LENGTH,
196
+ &transferred, 1000);
197
+ if (r < 0) {
198
+ fprintf(stderr, "intr error %d\n", r);
199
+ return r;
200
+ }
201
+ if (transferred < INTR_LENGTH) {
202
+ fprintf(stderr, "short read (%d)\n", r);
203
+ return -1;
204
+ }
205
+
206
+ printf("recv interrupt %04x\n", *((uint16_t *) data));
207
+ return 0;
208
+ }
209
+
210
+ static int sync_intr(unsigned char type)
211
+ {
212
+ int r;
213
+ unsigned char data[INTR_LENGTH];
214
+
215
+ while (1) {
216
+ r = do_sync_intr(data);
217
+ if (r < 0)
218
+ return r;
219
+ if (data[0] == type)
220
+ return 0;
221
+ }
222
+ }
223
+
224
+ static int save_to_file(unsigned char *data)
225
+ {
226
+ FILE *fd;
227
+ char filename[64];
228
+
229
+ snprintf(filename, sizeof(filename), "finger%d.pgm", img_idx++);
230
+ fd = fopen(filename, "w");
231
+ if (!fd)
232
+ return -1;
233
+
234
+ fputs("P5 384 289 255 ", fd);
235
+ (void) fwrite(data + 64, 1, 384*289, fd);
236
+ fclose(fd);
237
+ printf("saved image to %s\n", filename);
238
+ return 0;
239
+ }
240
+
241
+ static int next_state(void)
242
+ {
243
+ int r = 0;
244
+ printf("old state: %d\n", state);
245
+ switch (state) {
246
+ case STATE_AWAIT_IRQ_FINGER_REMOVED:
247
+ state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON;
248
+ r = set_mode_async(MODE_AWAIT_FINGER_ON);
249
+ break;
250
+ case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON:
251
+ state = STATE_AWAIT_IRQ_FINGER_DETECTED;
252
+ break;
253
+ case STATE_AWAIT_IRQ_FINGER_DETECTED:
254
+ state = STATE_AWAIT_MODE_CHANGE_CAPTURE;
255
+ r = set_mode_async(MODE_CAPTURE);
256
+ break;
257
+ case STATE_AWAIT_MODE_CHANGE_CAPTURE:
258
+ state = STATE_AWAIT_IMAGE;
259
+ break;
260
+ case STATE_AWAIT_IMAGE:
261
+ state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF;
262
+ r = set_mode_async(MODE_AWAIT_FINGER_OFF);
263
+ break;
264
+ case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF:
265
+ state = STATE_AWAIT_IRQ_FINGER_REMOVED;
266
+ break;
267
+ default:
268
+ printf("unrecognised state %d\n", state);
269
+ }
270
+ if (r < 0) {
271
+ fprintf(stderr, "error detected changing state\n");
272
+ return r;
273
+ }
274
+
275
+ printf("new state: %d\n", state);
276
+ return 0;
277
+ }
278
+
279
+ static void LIBUSB_CALL cb_irq(struct libusb_transfer *transfer)
280
+ {
281
+ unsigned char irqtype = transfer->buffer[0];
282
+
283
+ if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
284
+ fprintf(stderr, "irq transfer status %d?\n", transfer->status);
285
+ do_exit = 2;
286
+ libusb_free_transfer(transfer);
287
+ irq_transfer = NULL;
288
+ return;
289
+ }
290
+
291
+ printf("IRQ callback %02x\n", irqtype);
292
+ switch (state) {
293
+ case STATE_AWAIT_IRQ_FINGER_DETECTED:
294
+ if (irqtype == 0x01) {
295
+ if (next_state() < 0) {
296
+ do_exit = 2;
297
+ return;
298
+ }
299
+ } else {
300
+ printf("finger-on-sensor detected in wrong state!\n");
301
+ }
302
+ break;
303
+ case STATE_AWAIT_IRQ_FINGER_REMOVED:
304
+ if (irqtype == 0x02) {
305
+ if (next_state() < 0) {
306
+ do_exit = 2;
307
+ return;
308
+ }
309
+ } else {
310
+ printf("finger-on-sensor detected in wrong state!\n");
311
+ }
312
+ break;
313
+ }
314
+ if (libusb_submit_transfer(irq_transfer) < 0)
315
+ do_exit = 2;
316
+ }
317
+
318
+ static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer)
319
+ {
320
+ if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
321
+ fprintf(stderr, "img transfer status %d?\n", transfer->status);
322
+ do_exit = 2;
323
+ libusb_free_transfer(transfer);
324
+ img_transfer = NULL;
325
+ return;
326
+ }
327
+
328
+ printf("Image callback\n");
329
+ save_to_file(imgbuf);
330
+ if (next_state() < 0) {
331
+ do_exit = 2;
332
+ return;
333
+ }
334
+ if (libusb_submit_transfer(img_transfer) < 0)
335
+ do_exit = 2;
336
+ }
337
+
338
+ static int init_capture(void)
339
+ {
340
+ int r;
341
+
342
+ r = libusb_submit_transfer(irq_transfer);
343
+ if (r < 0)
344
+ return r;
345
+
346
+ r = libusb_submit_transfer(img_transfer);
347
+ if (r < 0) {
348
+ libusb_cancel_transfer(irq_transfer);
349
+ while (irq_transfer)
350
+ if (libusb_handle_events(NULL) < 0)
351
+ break;
352
+ return r;
353
+ }
354
+
355
+ /* start state machine */
356
+ state = STATE_AWAIT_IRQ_FINGER_REMOVED;
357
+ return next_state();
358
+ }
359
+
360
+ static int do_init(void)
361
+ {
362
+ unsigned char status;
363
+ int r;
364
+
365
+ r = get_hwstat(&status);
366
+ if (r < 0)
367
+ return r;
368
+
369
+ if (!(status & 0x80)) {
370
+ r = set_hwstat(status | 0x80);
371
+ if (r < 0)
372
+ return r;
373
+ r = get_hwstat(&status);
374
+ if (r < 0)
375
+ return r;
376
+ }
377
+
378
+ status &= ~0x80;
379
+ r = set_hwstat(status);
380
+ if (r < 0)
381
+ return r;
382
+
383
+ r = get_hwstat(&status);
384
+ if (r < 0)
385
+ return r;
386
+
387
+ r = sync_intr(0x56);
388
+ if (r < 0)
389
+ return r;
390
+
391
+ return 0;
392
+ }
393
+
394
+ static int alloc_transfers(void)
395
+ {
396
+ img_transfer = libusb_alloc_transfer(0);
397
+ if (!img_transfer)
398
+ return -ENOMEM;
399
+
400
+ irq_transfer = libusb_alloc_transfer(0);
401
+ if (!irq_transfer)
402
+ return -ENOMEM;
403
+
404
+ libusb_fill_bulk_transfer(img_transfer, devh, EP_DATA, imgbuf,
405
+ sizeof(imgbuf), cb_img, NULL, 0);
406
+ libusb_fill_interrupt_transfer(irq_transfer, devh, EP_INTR, irqbuf,
407
+ sizeof(irqbuf), cb_irq, NULL, 0);
408
+
409
+ return 0;
410
+ }
411
+
412
+ static void sighandler(int signum)
413
+ {
414
+ do_exit = 1;
415
+ }
416
+
417
+ int main(void)
418
+ {
419
+ struct sigaction sigact;
420
+ int r = 1;
421
+
422
+ r = libusb_init(NULL);
423
+ if (r < 0) {
424
+ fprintf(stderr, "failed to initialise libusb\n");
425
+ exit(1);
426
+ }
427
+
428
+ r = find_dpfp_device();
429
+ if (r < 0) {
430
+ fprintf(stderr, "Could not find/open device\n");
431
+ goto out;
432
+ }
433
+
434
+ r = libusb_claim_interface(devh, 0);
435
+ if (r < 0) {
436
+ fprintf(stderr, "usb_claim_interface error %d\n", r);
437
+ goto out;
438
+ }
439
+ printf("claimed interface\n");
440
+
441
+ r = print_f0_data();
442
+ if (r < 0)
443
+ goto out_release;
444
+
445
+ r = do_init();
446
+ if (r < 0)
447
+ goto out_deinit;
448
+
449
+ /* async from here onwards */
450
+
451
+ r = alloc_transfers();
452
+ if (r < 0)
453
+ goto out_deinit;
454
+
455
+ r = init_capture();
456
+ if (r < 0)
457
+ goto out_deinit;
458
+
459
+ sigact.sa_handler = sighandler;
460
+ sigemptyset(&sigact.sa_mask);
461
+ sigact.sa_flags = 0;
462
+ sigaction(SIGINT, &sigact, NULL);
463
+ sigaction(SIGTERM, &sigact, NULL);
464
+ sigaction(SIGQUIT, &sigact, NULL);
465
+
466
+ while (!do_exit) {
467
+ r = libusb_handle_events(NULL);
468
+ if (r < 0)
469
+ goto out_deinit;
470
+ }
471
+
472
+ printf("shutting down...\n");
473
+
474
+ if (irq_transfer) {
475
+ r = libusb_cancel_transfer(irq_transfer);
476
+ if (r < 0)
477
+ goto out_deinit;
478
+ }
479
+
480
+ if (img_transfer) {
481
+ r = libusb_cancel_transfer(img_transfer);
482
+ if (r < 0)
483
+ goto out_deinit;
484
+ }
485
+
486
+ while (irq_transfer || img_transfer)
487
+ if (libusb_handle_events(NULL) < 0)
488
+ break;
489
+
490
+ if (do_exit == 1)
491
+ r = 0;
492
+ else
493
+ r = 1;
494
+
495
+ out_deinit:
496
+ libusb_free_transfer(img_transfer);
497
+ libusb_free_transfer(irq_transfer);
498
+ set_mode(0);
499
+ set_hwstat(0x80);
500
+ out_release:
501
+ libusb_release_interface(devh, 0);
502
+ out:
503
+ libusb_close(devh);
504
+ libusb_exit(NULL);
505
+ return r >= 0 ? r : -r;
506
+ }