API renaming: remove fpi and usb_ stuff
[platform/upstream/libusb.git] / examples / dpfp.c
1 /*
2  * libusb example program to manipulate U.are.U 4000B fingerprint scanner.
3  * Copyright (C) 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 <signal.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28
29 #include <libusb/libusb.h>
30
31 #define EP_INTR                 (1 | LIBUSB_ENDPOINT_IN)
32 #define EP_DATA                 (2 | LIBUSB_ENDPOINT_IN)
33 #define CTRL_IN                 (LIBUSB_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)
34 #define CTRL_OUT                (LIBUSB_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT)
35 #define USB_RQ                  0x04
36 #define INTR_LENGTH             64
37
38 enum {
39         MODE_INIT = 0x00,
40         MODE_AWAIT_FINGER_ON = 0x10,
41         MODE_AWAIT_FINGER_OFF = 0x12,
42         MODE_CAPTURE = 0x20,
43         MODE_SHUT_UP = 0x30,
44         MODE_READY = 0x80,
45 };
46
47 static int next_state(void);
48 static int submit_irq_urb(void);
49 static int submit_img_urb(void);
50
51 enum {
52         STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1,
53         STATE_AWAIT_IRQ_FINGER_DETECTED,
54         STATE_AWAIT_MODE_CHANGE_CAPTURE,
55         STATE_AWAIT_IMAGE,
56         STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF,
57         STATE_AWAIT_IRQ_FINGER_REMOVED,
58 };
59
60 static int state = 0;
61 static struct libusb_dev_handle *devh = NULL;
62 static unsigned char imgbuf[0x1b340];
63 static unsigned char irqbuf[INTR_LENGTH];
64 static libusb_urb_handle *img_urbh = NULL;
65 static libusb_urb_handle *irq_urbh = NULL;
66 static int img_idx = 0;
67 static int do_exit = 0;
68
69 static struct libusb_bulk_msg imgmsg = {
70         .endpoint = EP_DATA,
71         .data = imgbuf,
72         .length = sizeof(imgbuf),
73 };
74
75 static struct libusb_bulk_msg irqmsg = {
76         .endpoint = EP_INTR,
77         .data = irqbuf,
78         .length = sizeof(irqbuf),
79 };
80
81 static struct libusb_dev *find_dpfp_device(void)
82 {
83         struct libusb_dev *dev;
84
85         libusb_find_devices();
86
87         for (dev = libusb_get_devices(); dev; dev = libusb_dev_next(dev)) {
88                 struct libusb_dev_descriptor *desc = libusb_dev_get_descriptor(dev);
89                 if (desc->idVendor == 0x05ba && desc->idProduct == 0x000a)
90                         return dev;
91         }
92
93         return NULL;
94 }
95
96 static int print_f0_data(void)
97 {
98         unsigned char data[0x10];
99         struct libusb_ctrl_msg msg = {
100                 .requesttype = CTRL_IN,
101                 .request = USB_RQ,
102                 .value = 0xf0,
103                 .index = 0,
104                 .length = sizeof(data),
105                 .data = data,
106         };
107         int r;
108         unsigned int i;
109
110         r = libusb_ctrl_msg(devh, &msg, 0);
111         if (r < 0) {
112                 fprintf(stderr, "F0 error %d\n", r);
113                 return r;
114         }
115         if ((unsigned int) r < sizeof(data)) {
116                 fprintf(stderr, "short read (%d)\n", r);
117                 return -1;
118         }
119
120         printf("F0 data:");
121         for (i = 0; i < sizeof(data); i++)
122                 printf("%02x ", data[i]);
123         printf("\n");
124         return 0;
125 }
126
127 static int get_hwstat(unsigned char *status)
128 {
129         struct libusb_ctrl_msg msg = {
130                 .requesttype = CTRL_IN,
131                 .request = USB_RQ,
132                 .value = 0x07,
133                 .index = 0,
134                 .length = 1,
135                 .data = status,
136         };
137         int r;
138
139         r = libusb_ctrl_msg(devh, &msg, 0);
140         if (r < 0) {
141                 fprintf(stderr, "read hwstat error %d\n", r);
142                 return r;
143         }
144         if ((unsigned int) r < 1) {
145                 fprintf(stderr, "short read (%d)\n", r);
146                 return -1;
147         }
148
149         printf("hwstat reads %02x\n", *status);
150         return 0;
151 }
152
153 static int set_hwstat(unsigned char data)
154 {
155         int r;
156         struct libusb_ctrl_msg msg = {
157                 .requesttype = CTRL_OUT,
158                 .request = USB_RQ,
159                 .value = 0x07,
160                 .index = 0,
161                 .length = 1,
162                 .data = &data,
163         };
164
165         printf("set hwstat to %02x\n", data);
166
167         r = libusb_ctrl_msg(devh, &msg, 0);
168         if (r < 0) {
169                 fprintf(stderr, "set hwstat error %d\n", r);
170                 return r;
171         }
172         if ((unsigned int) r < 1) {
173                 fprintf(stderr, "short write (%d)", r);
174                 return -1;
175         }
176
177         return 0;
178 }
179
180 static int set_mode(unsigned char data)
181 {
182         int r;
183         struct libusb_ctrl_msg msg = {
184                 .requesttype = CTRL_OUT,
185                 .request = USB_RQ,
186                 .value = 0x4e,
187                 .index = 0,
188                 .length = 1,
189                 .data = &data,
190         };
191
192         printf("set mode %02x\n", data);
193
194         r = libusb_ctrl_msg(devh, &msg, 0);
195         if (r < 0) {
196                 fprintf(stderr, "set mode error %d\n", r);
197                 return r;
198         }
199         if ((unsigned int) r < 1) {
200                 fprintf(stderr, "short write (%d)", r);
201                 return -1;
202         }
203
204         return 0;
205 }
206
207 static void cb_mode_changed(struct libusb_dev_handle *_devh,
208         struct libusb_urb_handle *urbh, enum fp_urb_cb_status status,
209         struct libusb_ctrl_setup *setup, unsigned char *data, int actual_length,
210         void *user_data)
211 {
212         if (status != FP_URB_COMPLETED) {
213                 fprintf(stderr, "mode change URB not completed!\n");
214                 do_exit = 2;
215         }
216
217         printf("async cb_mode_changed\n");
218         if (next_state() < 0)
219                 do_exit = 2;
220 }
221
222 static int set_mode_async(unsigned char data)
223 {
224         libusb_urb_handle *urbh;
225         struct libusb_ctrl_msg msg = {
226                 .requesttype = CTRL_OUT,
227                 .request = USB_RQ,
228                 .value = 0x4e,
229                 .index = 0,
230                 .length = 1,
231                 .data = &data,
232         };
233
234         printf("async set mode %02x\n", data);
235
236         urbh = libusb_submit_ctrl_msg(devh, &msg, cb_mode_changed, NULL, 1000);
237         if (!urbh) {
238                 fprintf(stderr, "set mode submit error\n");
239                 return -1;
240         }
241
242         return 0;
243 }
244
245 static int do_sync_intr(unsigned char *data)
246 {
247         struct libusb_bulk_msg msg = {
248                 .endpoint = EP_INTR,
249                 .data = data,
250                 .length = INTR_LENGTH,
251         };
252         int r;
253         int transferred;
254
255         r = libusb_intr_msg(devh, &msg, &transferred, 1000);
256         if (r < 0) {
257                 fprintf(stderr, "intr error %d\n", r);
258                 return r;
259         }
260         if (transferred < INTR_LENGTH) {
261                 fprintf(stderr, "short read (%d)\n", r);
262                 return -1;
263         }
264
265         printf("recv interrupt %04x\n", *((uint16_t *) data));
266         return 0;
267 }
268
269 static int sync_intr(unsigned char type)
270 {       
271         int r;
272         unsigned char data[INTR_LENGTH];
273
274         while (1) {
275                 r = do_sync_intr(data);
276                 if (r < 0)
277                         return r;
278                 if (data[0] == type)
279                         return 0;
280         }
281 }
282
283 static int save_to_file(unsigned char *data)
284 {
285         FILE *fd;
286         char filename[64];
287
288         sprintf(filename, "finger%d.pgm", img_idx++);
289         fd = fopen(filename, "w");
290         if (!fd)
291                 return -1;
292
293         fputs("P5 384 289 255 ", fd);
294         fwrite(data + 64, 1, 384*289, fd);
295         fclose(fd);
296         printf("saved image to %s\n", filename);
297         return 0;
298 }
299
300 static int next_state(void)
301 {
302         int r = 0;
303         printf("old state: %d\n", state);
304         switch (state) {
305         case STATE_AWAIT_IRQ_FINGER_REMOVED:
306                 state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON;
307                 r = set_mode_async(MODE_AWAIT_FINGER_ON);
308                 break;
309         case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON:
310                 state = STATE_AWAIT_IRQ_FINGER_DETECTED;
311                 break;
312         case STATE_AWAIT_IRQ_FINGER_DETECTED:
313                 state = STATE_AWAIT_MODE_CHANGE_CAPTURE;
314                 r = set_mode_async(MODE_CAPTURE);
315                 break;
316         case STATE_AWAIT_MODE_CHANGE_CAPTURE:
317                 state = STATE_AWAIT_IMAGE;
318                 break;
319         case STATE_AWAIT_IMAGE:
320                 state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF;
321                 r = set_mode_async(MODE_AWAIT_FINGER_OFF);
322                 break;
323         case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF:
324                 state = STATE_AWAIT_IRQ_FINGER_REMOVED;
325                 break;
326         default:
327                 printf("unrecognised state %d\n", state);
328         }
329         if (r < 0) {
330                 fprintf(stderr, "error detected changing state");
331                 return r;
332         }
333
334         printf("new state: %d\n", state);
335         return 0;
336 }
337
338 static void cb_irq(libusb_dev_handle *_devh, libusb_urb_handle *urbh,
339         enum fp_urb_cb_status status, unsigned char endpoint, int rqlength,
340         unsigned char *data, int actual_length, void *user_data)
341 {
342         unsigned char irqtype = data[0];
343
344         if (status != FP_URB_COMPLETED) {
345                 fprintf(stderr, "irq URB status %d?\n", status);
346                 do_exit = 2;
347                 return;
348         }
349
350         printf("IRQ callback %02x\n", irqtype);
351         switch (state) {
352         case STATE_AWAIT_IRQ_FINGER_DETECTED:
353                 if (irqtype == 0x01) {
354                         if (next_state() < 0) {
355                                 do_exit = 2;
356                                 return;
357                         }
358                 } else {
359                         printf("finger-on-sensor detected in wrong state!\n");
360                 }
361                 break;
362         case STATE_AWAIT_IRQ_FINGER_REMOVED:
363                 if (irqtype == 0x02) {
364                         if (next_state() < 0) {
365                                 do_exit = 2;
366                                 return;
367                         }
368                 } else {
369                         printf("finger-on-sensor detected in wrong state!\n");
370                 }
371                 break;
372         }
373         if (submit_irq_urb() < 0)
374                 do_exit = 2;
375 }
376
377 static void cb_img(libusb_dev_handle *_devh, libusb_urb_handle *urbh,
378         enum fp_urb_cb_status status, unsigned char endpoint, int rqlength,
379         unsigned char *data, int actual_length, void *user_data)
380 {
381         if (status != FP_URB_COMPLETED) {
382                 fprintf(stderr, "img URB status %d?\n", status);
383                 do_exit = 2;
384                 return;
385         }
386
387         printf("Image callback\n");
388         save_to_file(imgbuf);
389         if (next_state() < 0) {
390                 do_exit = 2;
391                 return;
392         }
393         if (submit_img_urb() < 0)
394                 do_exit = 2;
395 }
396
397 static int submit_irq_urb(void)
398 {
399         libusb_urb_handle_free(irq_urbh);
400         irq_urbh = libusb_submit_intr_msg(devh, &irqmsg, cb_irq, NULL, 0);
401         return irq_urbh != NULL;
402 }
403
404 static int submit_img_urb(void)
405 {
406         libusb_urb_handle_free(img_urbh);
407         img_urbh = libusb_submit_bulk_msg(devh, &imgmsg, cb_img, NULL, 0);
408         return img_urbh != NULL;
409 }
410
411 static int init_capture(void)
412 {
413         int r;
414
415         r = submit_irq_urb();
416         if (r < 0)
417                 return r;
418
419         r = submit_img_urb();
420         if (r < 0) {
421                 libusb_urb_handle_cancel_sync(devh, img_urbh);
422                 return r;
423         }
424
425         /* start state machine */
426         state = STATE_AWAIT_IRQ_FINGER_REMOVED;
427         return next_state();
428 }
429
430 static int do_init(void)
431 {
432         unsigned char status;
433         int r;
434
435         r = get_hwstat(&status);
436         if (r < 0)
437                 return r;
438
439         if (!(status & 0x80)) {
440                 r = set_hwstat(status | 0x80);
441                 if (r < 0)
442                         return r;
443                 r = get_hwstat(&status);
444                 if (r < 0)
445                         return r;
446         }
447
448         status &= ~0x80;
449         r = set_hwstat(status);
450         if (r < 0)
451                 return r;
452
453         r = get_hwstat(&status);
454         if (r < 0)
455                 return r;
456
457         r = sync_intr(0x56);
458         if (r < 0)
459                 return r;
460
461         return 0;
462 }
463
464 static void sighandler(int signum)
465 {
466         do_exit = 1;    
467 }
468
469 int main(void)
470 {
471         struct libusb_dev *dev;
472         struct sigaction sigact;
473         int r = 1;
474
475         r = libusb_init(0);
476         if (r < 0) {
477                 fprintf(stderr, "failed to initialise libusb\n");
478                 exit(1);
479         }
480
481         dev = find_dpfp_device();
482         if (!dev) {
483                 fprintf(stderr, "No device found\n");
484                 goto out;
485         }
486         printf("found device\n");
487
488         devh = libusb_devh_open(dev);
489         if (!devh) {
490                 fprintf(stderr, "Could not open device\n");
491                 goto out;
492         }
493         printf("opened device\n");
494
495         r = libusb_devh_claim_intf(devh, 0);
496         if (r < 0) {
497                 fprintf(stderr, "usb_claim_interface error %d %s\n", r, strerror(-r));
498                 goto out;
499         }
500         printf("claimed interface\n");
501
502         r = print_f0_data();
503         if (r < 0)
504                 goto out_release;
505
506         r = do_init();
507         if (r < 0)
508                 goto out_deinit;
509
510         /* async from here onwards */
511
512         r = init_capture();
513         if (r < 0)
514                 goto out_deinit;
515
516         sigact.sa_handler = sighandler;
517         sigemptyset(&sigact.sa_mask);
518         sigact.sa_flags = 0;
519         sigaction(SIGINT, &sigact, NULL);
520         sigaction(SIGTERM, &sigact, NULL);
521         sigaction(SIGQUIT, &sigact, NULL);
522
523         while (!do_exit) {
524                 r = libusb_poll();
525                 if (r < 0)
526                         goto out_deinit;
527         }
528
529         printf("shutting down...\n");
530
531         r = libusb_urb_handle_cancel_sync(devh, irq_urbh);
532         if (r < 0)
533                 goto out_deinit;
534
535         r = libusb_urb_handle_cancel_sync(devh, img_urbh);
536         if (r < 0)
537                 goto out_deinit;
538         
539         if (do_exit == 1)
540                 r = 0;
541         else
542                 r = 1;
543
544 out_deinit:
545         libusb_urb_handle_free(img_urbh);
546         libusb_urb_handle_free(irq_urbh);
547         set_mode(0);
548         set_hwstat(0x80);
549 out_release:
550         libusb_devh_release_intf(devh, 0);
551 out:
552         libusb_devh_close(devh);
553         libusb_exit();
554         return r >= 0 ? r : -r;
555 }
556