1 /* 2 * libusb example program to manipulate U.are.U 4000B fingerprint scanner. 3 * Copyright 2007 Daniel Drake <dsd (at) gentoo.org> 4 * Copyright 2016 Nathan Hjelm <hjelmn (at) mac.com> 5 * 6 * Basic image capture program only, does not consider the powerup quirks or 7 * the fact that image encryption may be enabled. Not expected to work 8 * flawlessly all of the time. 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; either 13 * version 2.1 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with this library; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 23 */ 24 25 #include <errno.h> 26 #include <pthread.h> 27 #include <semaphore.h> 28 #include <signal.h> 29 #include <string.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <fcntl.h> 33 34 #include "libusb.h" 35 36 #define EP_INTR (1 | LIBUSB_ENDPOINT_IN) 37 #define EP_DATA (2 | LIBUSB_ENDPOINT_IN) 38 #define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) 39 #define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT) 40 #define USB_RQ 0x04 41 #define INTR_LENGTH 64 42 #define SEM_NAME "/org.libusb.example.dpfp_threaded" 43 44 enum { 45 MODE_INIT = 0x00, 46 MODE_AWAIT_FINGER_ON = 0x10, 47 MODE_AWAIT_FINGER_OFF = 0x12, 48 MODE_CAPTURE = 0x20, 49 MODE_SHUT_UP = 0x30, 50 MODE_READY = 0x80, 51 }; 52 53 static int next_state(void); 54 55 enum { 56 STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1, 57 STATE_AWAIT_IRQ_FINGER_DETECTED, 58 STATE_AWAIT_MODE_CHANGE_CAPTURE, 59 STATE_AWAIT_IMAGE, 60 STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF, 61 STATE_AWAIT_IRQ_FINGER_REMOVED, 62 }; 63 64 static int state = 0; 65 static struct libusb_device_handle *devh = NULL; 66 static unsigned char imgbuf[0x1b340]; 67 static unsigned char irqbuf[INTR_LENGTH]; 68 static struct libusb_transfer *img_transfer = NULL; 69 static struct libusb_transfer *irq_transfer = NULL; 70 static int img_idx = 0; 71 static volatile sig_atomic_t do_exit = 0; 72 73 static pthread_t poll_thread; 74 static sem_t *exit_sem; 75 76 static void request_exit(sig_atomic_t code) 77 { 78 do_exit = code; 79 sem_post(exit_sem); 80 } 81 82 static void *poll_thread_main(void *arg) 83 { 84 int r = 0; 85 printf("poll thread running\n"); 86 87 while (!do_exit) { 88 struct timeval tv = { 1, 0 }; 89 r = libusb_handle_events_timeout(NULL, &tv); 90 if (r < 0) { 91 request_exit(2); 92 break; 93 } 94 } 95 96 printf("poll thread shutting down\n"); 97 return NULL; 98 } 99 100 static int find_dpfp_device(void) 101 { 102 devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a); 103 return devh ? 0 : -EIO; 104 } 105 106 static int print_f0_data(void) 107 { 108 unsigned char data[0x10]; 109 int r; 110 unsigned int i; 111 112 r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data, 113 sizeof(data), 0); 114 if (r < 0) { 115 fprintf(stderr, "F0 error %d\n", r); 116 return r; 117 } 118 if ((unsigned int) r < sizeof(data)) { 119 fprintf(stderr, "short read (%d)\n", r); 120 return -1; 121 } 122 123 printf("F0 data:"); 124 for (i = 0; i < sizeof(data); i++) 125 printf("%02x ", data[i]); 126 printf("\n"); 127 return 0; 128 } 129 130 static int get_hwstat(unsigned char *status) 131 { 132 int r; 133 134 r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0x07, 0, status, 1, 0); 135 if (r < 0) { 136 fprintf(stderr, "read hwstat error %d\n", r); 137 return r; 138 } 139 if ((unsigned int) r < 1) { 140 fprintf(stderr, "short read (%d)\n", r); 141 return -1; 142 } 143 144 printf("hwstat reads %02x\n", *status); 145 return 0; 146 } 147 148 static int set_hwstat(unsigned char data) 149 { 150 int r; 151 152 printf("set hwstat to %02x\n", data); 153 r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x07, 0, &data, 1, 0); 154 if (r < 0) { 155 fprintf(stderr, "set hwstat error %d\n", r); 156 return r; 157 } 158 if ((unsigned int) r < 1) { 159 fprintf(stderr, "short write (%d)", r); 160 return -1; 161 } 162 163 return 0; 164 } 165 166 static int set_mode(unsigned char data) 167 { 168 int r; 169 printf("set mode %02x\n", data); 170 171 r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0); 172 if (r < 0) { 173 fprintf(stderr, "set mode error %d\n", r); 174 return r; 175 } 176 if ((unsigned int) r < 1) { 177 fprintf(stderr, "short write (%d)", r); 178 return -1; 179 } 180 181 return 0; 182 } 183 184 static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer) 185 { 186 if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { 187 fprintf(stderr, "mode change transfer not completed!\n"); 188 request_exit(2); 189 } 190 191 printf("async cb_mode_changed length=%d actual_length=%d\n", 192 transfer->length, transfer->actual_length); 193 if (next_state() < 0) 194 request_exit(2); 195 } 196 197 static int set_mode_async(unsigned char data) 198 { 199 unsigned char *buf = (unsigned char*) malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); 200 struct libusb_transfer *transfer; 201 202 if (!buf) 203 return -ENOMEM; 204 205 transfer = libusb_alloc_transfer(0); 206 if (!transfer) { 207 free(buf); 208 return -ENOMEM; 209 } 210 211 printf("async set mode %02x\n", data); 212 libusb_fill_control_setup(buf, CTRL_OUT, USB_RQ, 0x4e, 0, 1); 213 buf[LIBUSB_CONTROL_SETUP_SIZE] = data; 214 libusb_fill_control_transfer(transfer, devh, buf, cb_mode_changed, NULL, 215 1000); 216 217 transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK 218 | LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; 219 return libusb_submit_transfer(transfer); 220 } 221 222 static int do_sync_intr(unsigned char *data) 223 { 224 int r; 225 int transferred; 226 227 r = libusb_interrupt_transfer(devh, EP_INTR, data, INTR_LENGTH, 228 &transferred, 1000); 229 if (r < 0) { 230 fprintf(stderr, "intr error %d\n", r); 231 return r; 232 } 233 if (transferred < INTR_LENGTH) { 234 fprintf(stderr, "short read (%d)\n", r); 235 return -1; 236 } 237 238 printf("recv interrupt %04x\n", *((uint16_t *) data)); 239 return 0; 240 } 241 242 static int sync_intr(unsigned char type) 243 { 244 int r; 245 unsigned char data[INTR_LENGTH]; 246 247 while (1) { 248 r = do_sync_intr(data); 249 if (r < 0) 250 return r; 251 if (data[0] == type) 252 return 0; 253 } 254 } 255 256 static int save_to_file(unsigned char *data) 257 { 258 FILE *fd; 259 char filename[64]; 260 261 snprintf(filename, sizeof(filename), "finger%d.pgm", img_idx++); 262 fd = fopen(filename, "w"); 263 if (!fd) 264 return -1; 265 266 fputs("P5 384 289 255 ", fd); 267 (void) fwrite(data + 64, 1, 384*289, fd); 268 fclose(fd); 269 printf("saved image to %s\n", filename); 270 return 0; 271 } 272 273 static int next_state(void) 274 { 275 int r = 0; 276 printf("old state: %d\n", state); 277 switch (state) { 278 case STATE_AWAIT_IRQ_FINGER_REMOVED: 279 state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON; 280 r = set_mode_async(MODE_AWAIT_FINGER_ON); 281 break; 282 case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON: 283 state = STATE_AWAIT_IRQ_FINGER_DETECTED; 284 break; 285 case STATE_AWAIT_IRQ_FINGER_DETECTED: 286 state = STATE_AWAIT_MODE_CHANGE_CAPTURE; 287 r = set_mode_async(MODE_CAPTURE); 288 break; 289 case STATE_AWAIT_MODE_CHANGE_CAPTURE: 290 state = STATE_AWAIT_IMAGE; 291 break; 292 case STATE_AWAIT_IMAGE: 293 state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF; 294 r = set_mode_async(MODE_AWAIT_FINGER_OFF); 295 break; 296 case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF: 297 state = STATE_AWAIT_IRQ_FINGER_REMOVED; 298 break; 299 default: 300 printf("unrecognised state %d\n", state); 301 } 302 if (r < 0) { 303 fprintf(stderr, "error detected changing state\n"); 304 return r; 305 } 306 307 printf("new state: %d\n", state); 308 return 0; 309 } 310 311 static void LIBUSB_CALL cb_irq(struct libusb_transfer *transfer) 312 { 313 unsigned char irqtype = transfer->buffer[0]; 314 315 if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { 316 fprintf(stderr, "irq transfer status %d?\n", transfer->status); 317 irq_transfer = NULL; 318 request_exit(2); 319 return; 320 } 321 322 printf("IRQ callback %02x\n", irqtype); 323 switch (state) { 324 case STATE_AWAIT_IRQ_FINGER_DETECTED: 325 if (irqtype == 0x01) { 326 if (next_state() < 0) { 327 request_exit(2); 328 return; 329 } 330 } else { 331 printf("finger-on-sensor detected in wrong state!\n"); 332 } 333 break; 334 case STATE_AWAIT_IRQ_FINGER_REMOVED: 335 if (irqtype == 0x02) { 336 if (next_state() < 0) { 337 request_exit(2); 338 return; 339 } 340 } else { 341 printf("finger-on-sensor detected in wrong state!\n"); 342 } 343 break; 344 } 345 if (libusb_submit_transfer(irq_transfer) < 0) 346 request_exit(2); 347 } 348 349 static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer) 350 { 351 if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { 352 fprintf(stderr, "img transfer status %d?\n", transfer->status); 353 img_transfer = NULL; 354 request_exit(2); 355 return; 356 } 357 358 printf("Image callback\n"); 359 save_to_file(imgbuf); 360 if (next_state() < 0) { 361 request_exit(2); 362 return; 363 } 364 if (libusb_submit_transfer(img_transfer) < 0) 365 request_exit(2); 366 } 367 368 static int init_capture(void) 369 { 370 int r; 371 372 r = libusb_submit_transfer(irq_transfer); 373 if (r < 0) 374 return r; 375 376 r = libusb_submit_transfer(img_transfer); 377 if (r < 0) { 378 libusb_cancel_transfer(irq_transfer); 379 while (irq_transfer) 380 if (libusb_handle_events(NULL) < 0) 381 break; 382 return r; 383 } 384 385 /* start state machine */ 386 state = STATE_AWAIT_IRQ_FINGER_REMOVED; 387 return next_state(); 388 } 389 390 static int do_init(void) 391 { 392 unsigned char status; 393 int r; 394 395 r = get_hwstat(&status); 396 if (r < 0) 397 return r; 398 399 if (!(status & 0x80)) { 400 r = set_hwstat(status | 0x80); 401 if (r < 0) 402 return r; 403 r = get_hwstat(&status); 404 if (r < 0) 405 return r; 406 } 407 408 status &= ~0x80; 409 r = set_hwstat(status); 410 if (r < 0) 411 return r; 412 413 r = get_hwstat(&status); 414 if (r < 0) 415 return r; 416 417 r = sync_intr(0x56); 418 if (r < 0) 419 return r; 420 421 return 0; 422 } 423 424 static int alloc_transfers(void) 425 { 426 img_transfer = libusb_alloc_transfer(0); 427 if (!img_transfer) 428 return -ENOMEM; 429 430 irq_transfer = libusb_alloc_transfer(0); 431 if (!irq_transfer) 432 return -ENOMEM; 433 434 libusb_fill_bulk_transfer(img_transfer, devh, EP_DATA, imgbuf, 435 sizeof(imgbuf), cb_img, NULL, 0); 436 libusb_fill_interrupt_transfer(irq_transfer, devh, EP_INTR, irqbuf, 437 sizeof(irqbuf), cb_irq, NULL, 0); 438 439 return 0; 440 } 441 442 static void sighandler(int signum) 443 { 444 request_exit(1); 445 } 446 447 int main(void) 448 { 449 struct sigaction sigact; 450 int r = 1; 451 452 exit_sem = sem_open (SEM_NAME, O_CREAT, 0); 453 if (!exit_sem) { 454 fprintf(stderr, "failed to initialise semaphore error %d", errno); 455 exit(1); 456 } 457 458 /* only using this semaphore in this process so go ahead and unlink it now */ 459 sem_unlink (SEM_NAME); 460 461 r = libusb_init(NULL); 462 if (r < 0) { 463 fprintf(stderr, "failed to initialise libusb\n"); 464 exit(1); 465 } 466 467 r = find_dpfp_device(); 468 if (r < 0) { 469 fprintf(stderr, "Could not find/open device\n"); 470 goto out; 471 } 472 473 r = libusb_claim_interface(devh, 0); 474 if (r < 0) { 475 fprintf(stderr, "usb_claim_interface error %d %s\n", r, strerror(-r)); 476 goto out; 477 } 478 printf("claimed interface\n"); 479 480 r = print_f0_data(); 481 if (r < 0) 482 goto out_release; 483 484 r = do_init(); 485 if (r < 0) 486 goto out_deinit; 487 488 /* async from here onwards */ 489 490 sigact.sa_handler = sighandler; 491 sigemptyset(&sigact.sa_mask); 492 sigact.sa_flags = 0; 493 sigaction(SIGINT, &sigact, NULL); 494 sigaction(SIGTERM, &sigact, NULL); 495 sigaction(SIGQUIT, &sigact, NULL); 496 497 r = pthread_create(&poll_thread, NULL, poll_thread_main, NULL); 498 if (r) 499 goto out_deinit; 500 501 r = alloc_transfers(); 502 if (r < 0) { 503 request_exit(1); 504 pthread_join(poll_thread, NULL); 505 goto out_deinit; 506 } 507 508 r = init_capture(); 509 if (r < 0) { 510 request_exit(1); 511 pthread_join(poll_thread, NULL); 512 goto out_deinit; 513 } 514 515 while (!do_exit) 516 sem_wait(exit_sem); 517 518 printf("shutting down...\n"); 519 pthread_join(poll_thread, NULL); 520 521 r = libusb_cancel_transfer(irq_transfer); 522 if (r < 0) { 523 request_exit(1); 524 goto out_deinit; 525 } 526 527 r = libusb_cancel_transfer(img_transfer); 528 if (r < 0) { 529 request_exit(1); 530 goto out_deinit; 531 } 532 533 while (img_transfer || irq_transfer) 534 if (libusb_handle_events(NULL) < 0) 535 break; 536 537 if (do_exit == 1) 538 r = 0; 539 else 540 r = 1; 541 542 out_deinit: 543 libusb_free_transfer(img_transfer); 544 libusb_free_transfer(irq_transfer); 545 set_mode(0); 546 set_hwstat(0x80); 547 out_release: 548 libusb_release_interface(devh, 0); 549 out: 550 libusb_close(devh); 551 libusb_exit(NULL); 552 return r >= 0 ? r : -r; 553 } 554