Fix issue 1) not recognizes some usb device, 2) reconnect when ffmpeg encoder error
[rtmpclient.git] / app / src / main / jni / libusb-1.0.22 / examples / dpfp.c
1 /*
2  * libusb 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         (void)signum;
415
416         do_exit = 1;
417 }
418
419 int main(void)
420 {
421         struct sigaction sigact;
422         int r;
423
424         r = libusb_init(NULL);
425         if (r < 0) {
426                 fprintf(stderr, "failed to initialise libusb\n");
427                 exit(1);
428         }
429
430         r = find_dpfp_device();
431         if (r < 0) {
432                 fprintf(stderr, "Could not find/open device\n");
433                 goto out;
434         }
435
436         r = libusb_claim_interface(devh, 0);
437         if (r < 0) {
438                 fprintf(stderr, "usb_claim_interface error %d\n", r);
439                 goto out;
440         }
441         printf("claimed interface\n");
442
443         r = print_f0_data();
444         if (r < 0)
445                 goto out_release;
446
447         r = do_init();
448         if (r < 0)
449                 goto out_deinit;
450
451         /* async from here onwards */
452
453         r = alloc_transfers();
454         if (r < 0)
455                 goto out_deinit;
456
457         r = init_capture();
458         if (r < 0)
459                 goto out_deinit;
460
461         sigact.sa_handler = sighandler;
462         sigemptyset(&sigact.sa_mask);
463         sigact.sa_flags = 0;
464         sigaction(SIGINT, &sigact, NULL);
465         sigaction(SIGTERM, &sigact, NULL);
466         sigaction(SIGQUIT, &sigact, NULL);
467
468         while (!do_exit) {
469                 r = libusb_handle_events(NULL);
470                 if (r < 0)
471                         goto out_deinit;
472         }
473
474         printf("shutting down...\n");
475
476         if (irq_transfer) {
477                 r = libusb_cancel_transfer(irq_transfer);
478                 if (r < 0)
479                         goto out_deinit;
480         }
481
482         if (img_transfer) {
483                 r = libusb_cancel_transfer(img_transfer);
484                 if (r < 0)
485                         goto out_deinit;
486         }
487
488         while (irq_transfer || img_transfer)
489                 if (libusb_handle_events(NULL) < 0)
490                         break;
491
492         if (do_exit == 1)
493                 r = 0;
494         else
495                 r = 1;
496
497 out_deinit:
498         libusb_free_transfer(img_transfer);
499         libusb_free_transfer(irq_transfer);
500         set_mode(0);
501         set_hwstat(0x80);
502 out_release:
503         libusb_release_interface(devh, 0);
504 out:
505         libusb_close(devh);
506         libusb_exit(NULL);
507         return r >= 0 ? r : -r;
508 }