2 * fpusb example program to manipulate U.are.U 4000B fingerprint scanner.
3 * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
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.
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.
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.
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
29 #include <libfpusb/fpusb.h>
31 #define EP_INTR (1 | USB_ENDPOINT_IN)
32 #define EP_DATA (2 | USB_ENDPOINT_IN)
33 #define CTRL_IN (USB_TYPE_VENDOR | USB_ENDPOINT_IN)
34 #define CTRL_OUT (USB_TYPE_VENDOR | USB_ENDPOINT_OUT)
36 #define INTR_LENGTH 64
40 MODE_AWAIT_FINGER_ON = 0x10,
41 MODE_AWAIT_FINGER_OFF = 0x12,
47 static int next_state(void);
48 static int submit_irq_urb(void);
49 static int submit_img_urb(void);
52 STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1,
53 STATE_AWAIT_IRQ_FINGER_DETECTED,
54 STATE_AWAIT_MODE_CHANGE_CAPTURE,
56 STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF,
57 STATE_AWAIT_IRQ_FINGER_REMOVED,
61 static struct fpusb_dev_handle *devh = NULL;
62 static unsigned char imgbuf[0x1b340];
63 static unsigned char irqbuf[INTR_LENGTH];
64 static fpusb_urb_handle *img_urbh = NULL;
65 static fpusb_urb_handle *irq_urbh = NULL;
66 static int img_idx = 0;
67 static int do_exit = 0;
69 static struct fpusb_bulk_msg imgmsg = {
72 .length = sizeof(imgbuf),
75 static struct fpusb_bulk_msg irqmsg = {
78 .length = sizeof(irqbuf),
81 static struct fpusb_dev *find_dpfp_device(void)
83 struct fpusb_dev *dev;
87 for (dev = fpusb_get_devices(); dev; dev = fpusb_dev_next(dev)) {
88 struct usb_dev_descriptor *desc = fpusb_dev_get_descriptor(dev);
89 if (desc->idVendor == 0x05ba && desc->idProduct == 0x000a)
96 static int print_f0_data(void)
98 unsigned char data[0x10];
99 struct fpusb_ctrl_msg msg = {
100 .requesttype = CTRL_IN,
104 .length = sizeof(data),
110 r = fpusb_ctrl_msg(devh, &msg, 0);
112 fprintf(stderr, "F0 error %d\n", r);
115 if ((unsigned int) r < sizeof(data)) {
116 fprintf(stderr, "short read (%d)\n", r);
121 for (i = 0; i < sizeof(data); i++)
122 printf("%02x ", data[i]);
127 static int get_hwstat(unsigned char *status)
129 struct fpusb_ctrl_msg msg = {
130 .requesttype = CTRL_IN,
139 r = fpusb_ctrl_msg(devh, &msg, 0);
141 fprintf(stderr, "read hwstat error %d\n", r);
144 if ((unsigned int) r < 1) {
145 fprintf(stderr, "short read (%d)\n", r);
149 printf("hwstat reads %02x\n", *status);
153 static int set_hwstat(unsigned char data)
156 struct fpusb_ctrl_msg msg = {
157 .requesttype = CTRL_OUT,
165 printf("set hwstat to %02x\n", data);
167 r = fpusb_ctrl_msg(devh, &msg, 0);
169 fprintf(stderr, "set hwstat error %d\n", r);
172 if ((unsigned int) r < 1) {
173 fprintf(stderr, "short write (%d)", r);
180 static int set_mode(unsigned char data)
183 struct fpusb_ctrl_msg msg = {
184 .requesttype = CTRL_OUT,
192 printf("set mode %02x\n", data);
194 r = fpusb_ctrl_msg(devh, &msg, 0);
196 fprintf(stderr, "set mode error %d\n", r);
199 if ((unsigned int) r < 1) {
200 fprintf(stderr, "short write (%d)", r);
207 static void cb_mode_changed(struct fpusb_dev_handle *_devh,
208 struct fpusb_urb_handle *urbh, struct fpusb_ctrl_msg *msg,
209 enum fp_urb_cb_status status, unsigned char *data, int actual_length,
212 if (status != FP_URB_COMPLETED) {
213 fprintf(stderr, "mode change URB not completed!\n");
217 printf("async cb_mode_changed\n");
218 if (next_state() < 0)
222 static int set_mode_async(unsigned char data)
224 fpusb_urb_handle *urbh;
225 struct fpusb_ctrl_msg msg = {
226 .requesttype = CTRL_OUT,
234 printf("async set mode %02x\n", data);
236 urbh = fpusb_submit_ctrl_msg(devh, &msg, cb_mode_changed, NULL, 1000);
238 fprintf(stderr, "set mode submit error\n");
245 static int do_sync_intr(unsigned char *data)
247 struct fpusb_bulk_msg msg = {
250 .length = INTR_LENGTH,
255 r = fpusb_intr_msg(devh, &msg, &transferred, 1000);
257 fprintf(stderr, "intr error %d\n", r);
260 if (transferred < INTR_LENGTH) {
261 fprintf(stderr, "short read (%d)\n", r);
265 printf("recv interrupt %04x\n", *((uint16_t *) data));
269 static int sync_intr(unsigned char type)
272 unsigned char data[INTR_LENGTH];
275 r = do_sync_intr(data);
283 static int save_to_file(unsigned char *data)
288 sprintf(filename, "finger%d.pgm", img_idx++);
289 fd = fopen(filename, "w");
293 fputs("P5 384 289 255 ", fd);
294 fwrite(data + 64, 1, 384*289, fd);
296 printf("saved image to %s\n", filename);
300 static int next_state(void)
303 printf("old state: %d\n", 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);
309 case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON:
310 state = STATE_AWAIT_IRQ_FINGER_DETECTED;
312 case STATE_AWAIT_IRQ_FINGER_DETECTED:
313 state = STATE_AWAIT_MODE_CHANGE_CAPTURE;
314 r = set_mode_async(MODE_CAPTURE);
316 case STATE_AWAIT_MODE_CHANGE_CAPTURE:
317 state = STATE_AWAIT_IMAGE;
319 case STATE_AWAIT_IMAGE:
320 state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF;
321 r = set_mode_async(MODE_AWAIT_FINGER_OFF);
323 case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF:
324 state = STATE_AWAIT_IRQ_FINGER_REMOVED;
327 printf("unrecognised state %d\n", state);
330 fprintf(stderr, "error detected changing state");
334 printf("new state: %d\n", state);
338 static void cb_irq(fpusb_dev_handle *_devh, fpusb_urb_handle *urbh,
339 struct fpusb_bulk_msg *msg, enum fp_urb_cb_status status,
340 int actual_length, void *user_data)
342 unsigned char irqtype = msg->data[0];
344 if (status != FP_URB_COMPLETED) {
345 fprintf(stderr, "irq URB status %d?\n", status);
350 printf("IRQ callback %02x\n", irqtype);
352 case STATE_AWAIT_IRQ_FINGER_DETECTED:
353 if (irqtype == 0x01) {
354 if (next_state() < 0) {
359 printf("finger-on-sensor detected in wrong state!\n");
362 case STATE_AWAIT_IRQ_FINGER_REMOVED:
363 if (irqtype == 0x02) {
364 if (next_state() < 0) {
369 printf("finger-on-sensor detected in wrong state!\n");
373 if (submit_irq_urb() < 0)
377 static void cb_img(fpusb_dev_handle *_devh, fpusb_urb_handle *urbh,
378 struct fpusb_bulk_msg *msg, enum fp_urb_cb_status status,
379 int actual_length, void *user_data)
381 if (status != FP_URB_COMPLETED) {
382 fprintf(stderr, "img URB status %d?\n", status);
387 printf("Image callback\n");
388 save_to_file(imgbuf);
389 if (next_state() < 0) {
393 if (submit_img_urb() < 0)
397 static int submit_irq_urb(void)
399 fpusb_urb_handle_free(irq_urbh);
400 irq_urbh = fpusb_submit_intr_msg(devh, &irqmsg, cb_irq, NULL, 0);
401 return irq_urbh != NULL;
404 static int submit_img_urb(void)
406 fpusb_urb_handle_free(img_urbh);
407 img_urbh = fpusb_submit_bulk_msg(devh, &imgmsg, cb_img, NULL, 0);
408 return img_urbh != NULL;
411 static int init_capture(void)
415 r = submit_irq_urb();
419 r = submit_img_urb();
421 fpusb_urb_handle_cancel_sync(devh, img_urbh);
425 /* start state machine */
426 state = STATE_AWAIT_IRQ_FINGER_REMOVED;
430 static int do_init(void)
432 unsigned char status;
435 r = get_hwstat(&status);
439 if (!(status & 0x80)) {
440 r = set_hwstat(status | 0x80);
443 r = get_hwstat(&status);
449 r = set_hwstat(status);
453 r = get_hwstat(&status);
464 static void sighandler(int signum)
471 struct fpusb_dev *dev;
472 struct sigaction sigact;
477 fprintf(stderr, "failed to initialise fpusb\n");
481 dev = find_dpfp_device();
483 fprintf(stderr, "No device found\n");
486 printf("found device\n");
488 devh = fpusb_devh_open(dev);
490 fprintf(stderr, "Could not open device\n");
493 printf("opened device\n");
495 r = fpusb_devh_claim_intf(devh, 0);
497 fprintf(stderr, "usb_claim_interface error %d %s\n", r, strerror(-r));
500 printf("claimed interface\n");
510 /* async from here onwards */
516 sigact.sa_handler = sighandler;
517 sigemptyset(&sigact.sa_mask);
519 sigaction(SIGINT, &sigact, NULL);
520 sigaction(SIGTERM, &sigact, NULL);
521 sigaction(SIGQUIT, &sigact, NULL);
529 printf("shutting down...\n");
531 r = fpusb_urb_handle_cancel_sync(devh, irq_urbh);
535 r = fpusb_urb_handle_cancel_sync(devh, img_urbh);
545 fpusb_urb_handle_free(img_urbh);
546 fpusb_urb_handle_free(irq_urbh);
550 fpusb_devh_release_intf(devh, 0);
552 fpusb_devh_close(devh);
554 return r >= 0 ? r : -r;