1 /* 2 * libusb example program to manipulate U.are.U 4000B fingerprint scanner. 3 * Copyright (C) 2007 Daniel Drake <dsd (at) 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/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 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 = 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 sprintf(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 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 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 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 } 507 508