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 <errno.h>
25 #include <pthread.h>
26 #include <signal.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 
31 #include <libusb/libusb.h>
32 
33 #define EP_INTR			(1 | LIBUSB_ENDPOINT_IN)
34 #define EP_DATA			(2 | LIBUSB_ENDPOINT_IN)
35 #define CTRL_IN			(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)
36 #define CTRL_OUT		(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT)
37 #define USB_RQ			0x04
38 #define INTR_LENGTH		64
39 
40 enum {
41 	MODE_INIT = 0x00,
42 	MODE_AWAIT_FINGER_ON = 0x10,
43 	MODE_AWAIT_FINGER_OFF = 0x12,
44 	MODE_CAPTURE = 0x20,
45 	MODE_SHUT_UP = 0x30,
46 	MODE_READY = 0x80,
47 };
48 
49 static int next_state(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_device_handle *devh = NULL;
62 static unsigned char imgbuf[0x1b340];
63 static unsigned char irqbuf[INTR_LENGTH];
64 static struct libusb_transfer *img_transfer = NULL;
65 static struct libusb_transfer *irq_transfer = NULL;
66 static int img_idx = 0;
67 static int do_exit = 0;
68 
69 static pthread_t poll_thread;
70 static pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
71 static pthread_mutex_t exit_cond_lock = PTHREAD_MUTEX_INITIALIZER;
72 
request_exit(int code)73 static void request_exit(int code)
74 {
75 	do_exit = code;
76 	pthread_cond_signal(&exit_cond);
77 }
78 
poll_thread_main(void * arg)79 static void *poll_thread_main(void *arg)
80 {
81 	int r = 0;
82 	printf("poll thread running\n");
83 
84 	while (!do_exit) {
85 		struct timeval tv = { 1, 0 };
86 		r = libusb_handle_events_timeout(NULL, &tv);
87 		if (r < 0) {
88 			request_exit(2);
89 			break;
90 		}
91 	}
92 
93 	printf("poll thread shutting down\n");
94 	pthread_exit(NULL);
95 }
96 
find_dpfp_device(void)97 static int find_dpfp_device(void)
98 {
99 	devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a);
100 	return devh ? 0 : -EIO;
101 }
102 
print_f0_data(void)103 static int print_f0_data(void)
104 {
105 	unsigned char data[0x10];
106 	int r;
107 	unsigned int i;
108 
109 	r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data,
110 		sizeof(data), 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 
get_hwstat(unsigned char * status)127 static int get_hwstat(unsigned char *status)
128 {
129 	int r;
130 
131 	r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0x07, 0, status, 1, 0);
132 	if (r < 0) {
133 		fprintf(stderr, "read hwstat error %d\n", r);
134 		return r;
135 	}
136 	if ((unsigned int) r < 1) {
137 		fprintf(stderr, "short read (%d)\n", r);
138 		return -1;
139 	}
140 
141 	printf("hwstat reads %02x\n", *status);
142 	return 0;
143 }
144 
set_hwstat(unsigned char data)145 static int set_hwstat(unsigned char data)
146 {
147 	int r;
148 
149 	printf("set hwstat to %02x\n", data);
150 	r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x07, 0, &data, 1, 0);
151 	if (r < 0) {
152 		fprintf(stderr, "set hwstat error %d\n", r);
153 		return r;
154 	}
155 	if ((unsigned int) r < 1) {
156 		fprintf(stderr, "short write (%d)", r);
157 		return -1;
158 	}
159 
160 	return 0;
161 }
162 
set_mode(unsigned char data)163 static int set_mode(unsigned char data)
164 {
165 	int r;
166 	printf("set mode %02x\n", data);
167 
168 	r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0);
169 	if (r < 0) {
170 		fprintf(stderr, "set mode error %d\n", r);
171 		return r;
172 	}
173 	if ((unsigned int) r < 1) {
174 		fprintf(stderr, "short write (%d)", r);
175 		return -1;
176 	}
177 
178 	return 0;
179 }
180 
cb_mode_changed(struct libusb_transfer * transfer)181 static void cb_mode_changed(struct libusb_transfer *transfer)
182 {
183 	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
184 		fprintf(stderr, "mode change transfer not completed!\n");
185 		request_exit(2);
186 	}
187 
188 	printf("async cb_mode_changed length=%d actual_length=%d\n",
189 		transfer->length, transfer->actual_length);
190 	if (next_state() < 0)
191 		request_exit(2);
192 }
193 
set_mode_async(unsigned char data)194 static int set_mode_async(unsigned char data)
195 {
196 	unsigned char *buf = malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
197 	struct libusb_transfer *transfer;
198 
199 	if (!buf)
200 		return -ENOMEM;
201 
202 	transfer = libusb_alloc_transfer(0);
203 	if (!transfer) {
204 		free(buf);
205 		return -ENOMEM;
206 	}
207 
208 	printf("async set mode %02x\n", data);
209 	libusb_fill_control_setup(buf, CTRL_OUT, USB_RQ, 0x4e, 0, 1);
210 	buf[LIBUSB_CONTROL_SETUP_SIZE] = data;
211 	libusb_fill_control_transfer(transfer, devh, buf, cb_mode_changed, NULL,
212 		1000);
213 
214 	transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK
215 		| LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
216 	return libusb_submit_transfer(transfer);
217 }
218 
do_sync_intr(unsigned char * data)219 static int do_sync_intr(unsigned char *data)
220 {
221 	int r;
222 	int transferred;
223 
224 	r = libusb_interrupt_transfer(devh, EP_INTR, data, INTR_LENGTH,
225 		&transferred, 1000);
226 	if (r < 0) {
227 		fprintf(stderr, "intr error %d\n", r);
228 		return r;
229 	}
230 	if (transferred < INTR_LENGTH) {
231 		fprintf(stderr, "short read (%d)\n", r);
232 		return -1;
233 	}
234 
235 	printf("recv interrupt %04x\n", *((uint16_t *) data));
236 	return 0;
237 }
238 
sync_intr(unsigned char type)239 static int sync_intr(unsigned char type)
240 {
241 	int r;
242 	unsigned char data[INTR_LENGTH];
243 
244 	while (1) {
245 		r = do_sync_intr(data);
246 		if (r < 0)
247 			return r;
248 		if (data[0] == type)
249 			return 0;
250 	}
251 }
252 
save_to_file(unsigned char * data)253 static int save_to_file(unsigned char *data)
254 {
255 	FILE *fd;
256 	char filename[64];
257 
258 	sprintf(filename, "finger%d.pgm", img_idx++);
259 	fd = fopen(filename, "w");
260 	if (!fd)
261 		return -1;
262 
263 	fputs("P5 384 289 255 ", fd);
264 	fwrite(data + 64, 1, 384*289, fd);
265 	fclose(fd);
266 	printf("saved image to %s\n", filename);
267 	return 0;
268 }
269 
next_state(void)270 static int next_state(void)
271 {
272 	int r = 0;
273 	printf("old state: %d\n", state);
274 	switch (state) {
275 	case STATE_AWAIT_IRQ_FINGER_REMOVED:
276 		state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON;
277 		r = set_mode_async(MODE_AWAIT_FINGER_ON);
278 		break;
279 	case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON:
280 		state = STATE_AWAIT_IRQ_FINGER_DETECTED;
281 		break;
282 	case STATE_AWAIT_IRQ_FINGER_DETECTED:
283 		state = STATE_AWAIT_MODE_CHANGE_CAPTURE;
284 		r = set_mode_async(MODE_CAPTURE);
285 		break;
286 	case STATE_AWAIT_MODE_CHANGE_CAPTURE:
287 		state = STATE_AWAIT_IMAGE;
288 		break;
289 	case STATE_AWAIT_IMAGE:
290 		state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF;
291 		r = set_mode_async(MODE_AWAIT_FINGER_OFF);
292 		break;
293 	case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF:
294 		state = STATE_AWAIT_IRQ_FINGER_REMOVED;
295 		break;
296 	default:
297 		printf("unrecognised state %d\n", state);
298 	}
299 	if (r < 0) {
300 		fprintf(stderr, "error detected changing state\n");
301 		return r;
302 	}
303 
304 	printf("new state: %d\n", state);
305 	return 0;
306 }
307 
cb_irq(struct libusb_transfer * transfer)308 static void cb_irq(struct libusb_transfer *transfer)
309 {
310 	unsigned char irqtype = transfer->buffer[0];
311 
312 	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
313 		fprintf(stderr, "irq transfer status %d?\n", transfer->status);
314 		irq_transfer = NULL;
315 		request_exit(2);
316 		return;
317 	}
318 
319 	printf("IRQ callback %02x\n", irqtype);
320 	switch (state) {
321 	case STATE_AWAIT_IRQ_FINGER_DETECTED:
322 		if (irqtype == 0x01) {
323 			if (next_state() < 0) {
324 				request_exit(2);
325 				return;
326 			}
327 		} else {
328 			printf("finger-on-sensor detected in wrong state!\n");
329 		}
330 		break;
331 	case STATE_AWAIT_IRQ_FINGER_REMOVED:
332 		if (irqtype == 0x02) {
333 			if (next_state() < 0) {
334 				request_exit(2);
335 				return;
336 			}
337 		} else {
338 			printf("finger-on-sensor detected in wrong state!\n");
339 		}
340 		break;
341 	}
342 	if (libusb_submit_transfer(irq_transfer) < 0)
343 		request_exit(2);
344 }
345 
cb_img(struct libusb_transfer * transfer)346 static void cb_img(struct libusb_transfer *transfer)
347 {
348 	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
349 		fprintf(stderr, "img transfer status %d?\n", transfer->status);
350 		img_transfer = NULL;
351 		request_exit(2);
352 		return;
353 	}
354 
355 	printf("Image callback\n");
356 	save_to_file(imgbuf);
357 	if (next_state() < 0) {
358 		request_exit(2);
359 		return;
360 	}
361 	if (libusb_submit_transfer(img_transfer) < 0)
362 		request_exit(2);
363 }
364 
init_capture(void)365 static int init_capture(void)
366 {
367 	int r;
368 
369 	r = libusb_submit_transfer(irq_transfer);
370 	if (r < 0)
371 		return r;
372 
373 	r = libusb_submit_transfer(img_transfer);
374 	if (r < 0) {
375 		libusb_cancel_transfer(irq_transfer);
376 		while (irq_transfer)
377 			if (libusb_handle_events(NULL) < 0)
378 				break;
379 		return r;
380 	}
381 
382 	/* start state machine */
383 	state = STATE_AWAIT_IRQ_FINGER_REMOVED;
384 	return next_state();
385 }
386 
do_init(void)387 static int do_init(void)
388 {
389 	unsigned char status;
390 	int r;
391 
392 	r = get_hwstat(&status);
393 	if (r < 0)
394 		return r;
395 
396 	if (!(status & 0x80)) {
397 		r = set_hwstat(status | 0x80);
398 		if (r < 0)
399 			return r;
400 		r = get_hwstat(&status);
401 		if (r < 0)
402 			return r;
403 	}
404 
405 	status &= ~0x80;
406 	r = set_hwstat(status);
407 	if (r < 0)
408 		return r;
409 
410 	r = get_hwstat(&status);
411 	if (r < 0)
412 		return r;
413 
414 	r = sync_intr(0x56);
415 	if (r < 0)
416 		return r;
417 
418 	return 0;
419 }
420 
alloc_transfers(void)421 static int alloc_transfers(void)
422 {
423 	img_transfer = libusb_alloc_transfer(0);
424 	if (!img_transfer)
425 		return -ENOMEM;
426 
427 	irq_transfer = libusb_alloc_transfer(0);
428 	if (!irq_transfer)
429 		return -ENOMEM;
430 
431 	libusb_fill_bulk_transfer(img_transfer, devh, EP_DATA, imgbuf,
432 		sizeof(imgbuf), cb_img, NULL, 0);
433 	libusb_fill_interrupt_transfer(irq_transfer, devh, EP_INTR, irqbuf,
434 		sizeof(irqbuf), cb_irq, NULL, 0);
435 
436 	return 0;
437 }
438 
sighandler(int signum)439 static void sighandler(int signum)
440 {
441 	request_exit(1);
442 }
443 
main(void)444 int main(void)
445 {
446 	struct sigaction sigact;
447 	int r = 1;
448 
449 	r = libusb_init(NULL);
450 	if (r < 0) {
451 		fprintf(stderr, "failed to initialise libusb\n");
452 		exit(1);
453 	}
454 
455 	r = find_dpfp_device();
456 	if (r < 0) {
457 		fprintf(stderr, "Could not find/open device\n");
458 		goto out;
459 	}
460 
461 	r = libusb_claim_interface(devh, 0);
462 	if (r < 0) {
463 		fprintf(stderr, "usb_claim_interface error %d %s\n", r, strerror(-r));
464 		goto out;
465 	}
466 	printf("claimed interface\n");
467 
468 	r = print_f0_data();
469 	if (r < 0)
470 		goto out_release;
471 
472 	r = do_init();
473 	if (r < 0)
474 		goto out_deinit;
475 
476 	/* async from here onwards */
477 
478 	sigact.sa_handler = sighandler;
479 	sigemptyset(&sigact.sa_mask);
480 	sigact.sa_flags = 0;
481 	sigaction(SIGINT, &sigact, NULL);
482 	sigaction(SIGTERM, &sigact, NULL);
483 	sigaction(SIGQUIT, &sigact, NULL);
484 
485 	r = pthread_create(&poll_thread, NULL, poll_thread_main, NULL);
486 	if (r)
487 		goto out_deinit;
488 
489 	r = alloc_transfers();
490 	if (r < 0) {
491 		request_exit(1);
492 		pthread_join(poll_thread, NULL);
493 		goto out_deinit;
494 	}
495 
496 	r = init_capture();
497 	if (r < 0) {
498 		request_exit(1);
499 		pthread_join(poll_thread, NULL);
500 		goto out_deinit;
501 	}
502 
503 	while (!do_exit) {
504 		pthread_mutex_lock(&exit_cond_lock);
505 		pthread_cond_wait(&exit_cond, &exit_cond_lock);
506 		pthread_mutex_unlock(&exit_cond_lock);
507 	}
508 
509 	printf("shutting down...\n");
510 	pthread_join(poll_thread, NULL);
511 
512 	r = libusb_cancel_transfer(irq_transfer);
513 	if (r < 0) {
514 		request_exit(1);
515 		goto out_deinit;
516 	}
517 
518 	r = libusb_cancel_transfer(img_transfer);
519 	if (r < 0) {
520 		request_exit(1);
521 		goto out_deinit;
522 	}
523 
524 	while (img_transfer || irq_transfer)
525 		if (libusb_handle_events(NULL) < 0)
526 			break;
527 
528 	if (do_exit == 1)
529 		r = 0;
530 	else
531 		r = 1;
532 
533 out_deinit:
534 	libusb_free_transfer(img_transfer);
535 	libusb_free_transfer(irq_transfer);
536 	set_mode(0);
537 	set_hwstat(0x80);
538 out_release:
539 	libusb_release_interface(devh, 0);
540 out:
541 	libusb_close(devh);
542 	libusb_exit(NULL);
543 	return r >= 0 ? r : -r;
544 }
545 
546