Home | History | Annotate | Download | only in examples
      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