dpfp.c 15 KB

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