Use "transfer" instead of "msg"
[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_transfer imgtrf = {
70         .endpoint = EP_DATA,
71         .data = imgbuf,
72         .length = sizeof(imgbuf),
73 };
74
75 static struct libusb_bulk_transfer irqtrf = {
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_control_transfer transfer = {
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_control_transfer(devh, &transfer, 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_control_transfer transfer = {
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_control_transfer(devh, &transfer, 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_control_transfer transfer = {
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_control_transfer(devh, &transfer, 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_control_transfer transfer = {
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_control_transfer(devh, &transfer, 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_control_transfer transfer = {
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_async_control_transfer(devh, &transfer, cb_mode_changed, NULL,
237                 1000);
238         if (!urbh) {
239                 fprintf(stderr, "set mode submit error\n");
240                 return -1;
241         }
242
243         return 0;
244 }
245
246 static int do_sync_intr(unsigned char *data)
247 {
248         struct libusb_bulk_transfer transfer = {
249                 .endpoint = EP_INTR,
250                 .data = data,
251                 .length = INTR_LENGTH,
252         };
253         int r;
254         int transferred;
255
256         r = libusb_interrupt_transfer(devh, &transfer, &transferred, 1000);
257         if (r < 0) {
258                 fprintf(stderr, "intr error %d\n", r);
259                 return r;
260         }
261         if (transferred < INTR_LENGTH) {
262                 fprintf(stderr, "short read (%d)\n", r);
263                 return -1;
264         }
265
266         printf("recv interrupt %04x\n", *((uint16_t *) data));
267         return 0;
268 }
269
270 static int sync_intr(unsigned char type)
271 {       
272         int r;
273         unsigned char data[INTR_LENGTH];
274
275         while (1) {
276                 r = do_sync_intr(data);
277                 if (r < 0)
278                         return r;
279                 if (data[0] == type)
280                         return 0;
281         }
282 }
283
284 static int save_to_file(unsigned char *data)
285 {
286         FILE *fd;
287         char filename[64];
288
289         sprintf(filename, "finger%d.pgm", img_idx++);
290         fd = fopen(filename, "w");
291         if (!fd)
292                 return -1;
293
294         fputs("P5 384 289 255 ", fd);
295         fwrite(data + 64, 1, 384*289, fd);
296         fclose(fd);
297         printf("saved image to %s\n", filename);
298         return 0;
299 }
300
301 static int next_state(void)
302 {
303         int r = 0;
304         printf("old state: %d\n", state);
305         switch (state) {
306         case STATE_AWAIT_IRQ_FINGER_REMOVED:
307                 state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON;
308                 r = set_mode_async(MODE_AWAIT_FINGER_ON);
309                 break;
310         case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON:
311                 state = STATE_AWAIT_IRQ_FINGER_DETECTED;
312                 break;
313         case STATE_AWAIT_IRQ_FINGER_DETECTED:
314                 state = STATE_AWAIT_MODE_CHANGE_CAPTURE;
315                 r = set_mode_async(MODE_CAPTURE);
316                 break;
317         case STATE_AWAIT_MODE_CHANGE_CAPTURE:
318                 state = STATE_AWAIT_IMAGE;
319                 break;
320         case STATE_AWAIT_IMAGE:
321                 state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF;
322                 r = set_mode_async(MODE_AWAIT_FINGER_OFF);
323                 break;
324         case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF:
325                 state = STATE_AWAIT_IRQ_FINGER_REMOVED;
326                 break;
327         default:
328                 printf("unrecognised state %d\n", state);
329         }
330         if (r < 0) {
331                 fprintf(stderr, "error detected changing state");
332                 return r;
333         }
334
335         printf("new state: %d\n", state);
336         return 0;
337 }
338
339 static void cb_irq(libusb_dev_handle *_devh, libusb_urb_handle *urbh,
340         enum fp_urb_cb_status status, unsigned char endpoint, int rqlength,
341         unsigned char *data, int actual_length, void *user_data)
342 {
343         unsigned char irqtype = data[0];
344
345         if (status != FP_URB_COMPLETED) {
346                 fprintf(stderr, "irq URB status %d?\n", status);
347                 do_exit = 2;
348                 return;
349         }
350
351         printf("IRQ callback %02x\n", irqtype);
352         switch (state) {
353         case STATE_AWAIT_IRQ_FINGER_DETECTED:
354                 if (irqtype == 0x01) {
355                         if (next_state() < 0) {
356                                 do_exit = 2;
357                                 return;
358                         }
359                 } else {
360                         printf("finger-on-sensor detected in wrong state!\n");
361                 }
362                 break;
363         case STATE_AWAIT_IRQ_FINGER_REMOVED:
364                 if (irqtype == 0x02) {
365                         if (next_state() < 0) {
366                                 do_exit = 2;
367                                 return;
368                         }
369                 } else {
370                         printf("finger-on-sensor detected in wrong state!\n");
371                 }
372                 break;
373         }
374         if (submit_irq_urb() < 0)
375                 do_exit = 2;
376 }
377
378 static void cb_img(libusb_dev_handle *_devh, libusb_urb_handle *urbh,
379         enum fp_urb_cb_status status, unsigned char endpoint, int rqlength,
380         unsigned char *data, int actual_length, void *user_data)
381 {
382         if (status != FP_URB_COMPLETED) {
383                 fprintf(stderr, "img URB status %d?\n", status);
384                 do_exit = 2;
385                 return;
386         }
387
388         printf("Image callback\n");
389         save_to_file(imgbuf);
390         if (next_state() < 0) {
391                 do_exit = 2;
392                 return;
393         }
394         if (submit_img_urb() < 0)
395                 do_exit = 2;
396 }
397
398 static int submit_irq_urb(void)
399 {
400         libusb_urb_handle_free(irq_urbh);
401         irq_urbh = libusb_async_interrupt_transfer(devh, &irqtrf, cb_irq, NULL, 0);
402         return irq_urbh != NULL;
403 }
404
405 static int submit_img_urb(void)
406 {
407         libusb_urb_handle_free(img_urbh);
408         img_urbh = libusb_async_bulk_transfer(devh, &imgtrf, cb_img, NULL, 0);
409         return img_urbh != NULL;
410 }
411
412 static int init_capture(void)
413 {
414         int r;
415
416         r = submit_irq_urb();
417         if (r < 0)
418                 return r;
419
420         r = submit_img_urb();
421         if (r < 0) {
422                 libusb_urb_handle_cancel_sync(devh, img_urbh);
423                 return r;
424         }
425
426         /* start state machine */
427         state = STATE_AWAIT_IRQ_FINGER_REMOVED;
428         return next_state();
429 }
430
431 static int do_init(void)
432 {
433         unsigned char status;
434         int r;
435
436         r = get_hwstat(&status);
437         if (r < 0)
438                 return r;
439
440         if (!(status & 0x80)) {
441                 r = set_hwstat(status | 0x80);
442                 if (r < 0)
443                         return r;
444                 r = get_hwstat(&status);
445                 if (r < 0)
446                         return r;
447         }
448
449         status &= ~0x80;
450         r = set_hwstat(status);
451         if (r < 0)
452                 return r;
453
454         r = get_hwstat(&status);
455         if (r < 0)
456                 return r;
457
458         r = sync_intr(0x56);
459         if (r < 0)
460                 return r;
461
462         return 0;
463 }
464
465 static void sighandler(int signum)
466 {
467         do_exit = 1;    
468 }
469
470 int main(void)
471 {
472         struct libusb_dev *dev;
473         struct sigaction sigact;
474         int r = 1;
475
476         r = libusb_init(0);
477         if (r < 0) {
478                 fprintf(stderr, "failed to initialise libusb\n");
479                 exit(1);
480         }
481
482         dev = find_dpfp_device();
483         if (!dev) {
484                 fprintf(stderr, "No device found\n");
485                 goto out;
486         }
487         printf("found device\n");
488
489         devh = libusb_devh_open(dev);
490         if (!devh) {
491                 fprintf(stderr, "Could not open device\n");
492                 goto out;
493         }
494         printf("opened device\n");
495
496         r = libusb_devh_claim_intf(devh, 0);
497         if (r < 0) {
498                 fprintf(stderr, "usb_claim_interface error %d %s\n", r, strerror(-r));
499                 goto out;
500         }
501         printf("claimed interface\n");
502
503         r = print_f0_data();
504         if (r < 0)
505                 goto out_release;
506
507         r = do_init();
508         if (r < 0)
509                 goto out_deinit;
510
511         /* async from here onwards */
512
513         r = init_capture();
514         if (r < 0)
515                 goto out_deinit;
516
517         sigact.sa_handler = sighandler;
518         sigemptyset(&sigact.sa_mask);
519         sigact.sa_flags = 0;
520         sigaction(SIGINT, &sigact, NULL);
521         sigaction(SIGTERM, &sigact, NULL);
522         sigaction(SIGQUIT, &sigact, NULL);
523
524         while (!do_exit) {
525                 r = libusb_poll();
526                 if (r < 0)
527                         goto out_deinit;
528         }
529
530         printf("shutting down...\n");
531
532         r = libusb_urb_handle_cancel_sync(devh, irq_urbh);
533         if (r < 0)
534                 goto out_deinit;
535
536         r = libusb_urb_handle_cancel_sync(devh, img_urbh);
537         if (r < 0)
538                 goto out_deinit;
539         
540         if (do_exit == 1)
541                 r = 0;
542         else
543                 r = 1;
544
545 out_deinit:
546         libusb_urb_handle_free(img_urbh);
547         libusb_urb_handle_free(irq_urbh);
548         set_mode(0);
549         set_hwstat(0x80);
550 out_release:
551         libusb_devh_release_intf(devh, 0);
552 out:
553         libusb_devh_close(devh);
554         libusb_exit();
555         return r >= 0 ? r : -r;
556 }
557