~ubuntu-branches/ubuntu/karmic/thinkfinger/karmic

1 by Luca Capello
Import upstream version 0.3
1
/*
2
 *   ThinkFinger - A driver for the UPEK/SGS Thomson Microelectronics
3
 *   fingerprint reader.
4
 *
5
 *   Copyright (C) 2006 Pavel Machek <pavel@suse.cz>
6
 *                      Timo Hoenig <thoenig@suse.de>
7
 *
8
 *   Copyright (C) 2007 Timo Hoenig <thoenig@suse.de>
9
 *
10
 *   This program is free software; you can redistribute it and/or modify
11
 *   it under the terms of the GNU General Public License as published by
12
 *   the Free Software Foundation; either version 2 of the License, or
13
 *   (at your option) any later version.
14
 *
15
 *   This program 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
18
 *   GNU General Public License for more details.
19
 *
20
 *   You should have received a copy of the GNU General Public License
21
 *   along with this program; if not, write to the
22
 *   Free Software Foundation, Inc.,
23
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24
 *
25
 *   TODO: move this to documentation
26
 *   Hardware should be 248 x 4 pixels, 8bit per pixel, but seems to do matching
27
 *   completely in hardware.
28
 *
29
 *   TODO: this is not true for all distributions
30
 *   Note that you need to be root to use this.
31
 */
32
33
#include "libthinkfinger.h"
34
#include "libthinkfinger-crc.h"
35
36
#define USB_VENDOR_ID     0x0483
37
#define USB_PRODUCT_ID    0x2016
38
#define USB_TIMEOUT       5000
39
#define USB_WR_EP         0x02
40
#define USB_RD_EP         0x81
41
#define DEFAULT_BULK_SIZE 0x40
42
#define INITIAL_SEQUENCE  0x60
43
44
static char init_a[17] = {
45
	0x43, 0x69, 0x61, 0x6f, 0x04, 0x00, 0x08, 0x01,
46
	0x00, 0xe8, 0x03, 0x00, 0x00, 0xff, 0x07, 0xdb,
47
	0x24
48
};
49
50
static char init_b[16] = {
51
	0x43, 0x69, 0x61, 0x6f, 0x00, 0x00, 0x07, 0x28,
52
	0x04, 0x00, 0x00, 0x00, 0x06, 0x04, 0xc0, 0xd6
53
};
54
55
static char init_c[16] = {
56
	0x43, 0x69, 0x61, 0x6f, 0x00, 0x10, 0x07, 0x28,
57
	0x04, 0x00, 0x00, 0x00, 0x07, 0x04, 0x0f, 0xb6
58
};
59
60
/* TODO: dynamic */
61
static char init_d[40] = {
62
	0x43, 0x69, 0x61, 0x6f, 0x00, 0x20, 0x1f, 0x28,
63
	0x1c, 0x00, 0x00, 0x00, 0x08, 0x04, 0x83, 0x00,
64
	0x2c, 0x22, 0x23, 0x97, 0xc9, 0xa7, 0x15, 0xa0,
65
	0x8a, 0xab, 0x3c, 0xd0, 0xbf, 0xdb, 0xf3, 0x92,
66
	0x6f, 0xae, 0x3b, 0x1e, 0x44, 0xc4, 0x9a, 0x45
67
};
68
69
static char init_e[20] = {
70
	0x43, 0x69, 0x61, 0x6f, 0x00, 0x30, 0x0b, 0x28,
71
	0x08, 0x00, 0x00, 0x00, 0x0c, 0x04, 0x03, 0x00,
72
	0x00, 0x00, 0x6d, 0x7e
73
};
74
75
/* TODO: dynamic */
76
static char init_end[120] = {
77
	0x43, 0x69, 0x61, 0x6f, 0x00, 0x40, 0x6f, 0x28,
78
	0x6c, 0x00, 0x00, 0x00, 0x0b, 0x04, 0x03, 0x00,
79
	0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00,
80
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
81
	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
82
	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
83
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x01,
84
	0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00,
85
	0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
86
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
87
	0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
88
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
89
	0x0a, 0x00, 0x64, 0x00, 0xf4, 0x01, 0x32, 0x00,
90
	0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
91
	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xd6, 0x66
92
};
93
94
static char deinit[10] = {
95
	0x43, 0x69, 0x61, 0x6f, 0x07, 0x00, 0x01, 0x00,
96
	0x1c, 0x62
97
};
98
99
static char device_busy[9] = {
100
	0x43, 0x69, 0x61, 0x6f, 0x09, 0x00, 0x00, 0x91,
101
	0x9e
102
};
103
104
struct init_table {
105
	char *data;
106
	size_t len;
107
};
108
109
static struct init_table init[] = {
110
	{ init_a, sizeof (init_a) },
111
	{ init_b, sizeof (init_b) },
112
	{ init_c, sizeof (init_c) },
113
	{ init_d, sizeof (init_d) },
114
	{ init_e, sizeof (init_e) },
115
	{ 0x0,    0x0 }
116
};
117
118
static char ctrlbuf[1024] = {
119
	0x43, 0x69, 0x61, 0x6f, 0x00, 0x51, 0x0b, 0x28,
120
	0xb8, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00,
121
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122
	0x00, 0x00, 0xc0, 0xd4, 0x01, 0x00, 0x20, 0x00,
123
	0x00, 0x00, 0x03
124
};
125
126
static char enroll_init[23] = {
127
	0x43, 0x69, 0x61, 0x6f, 0x00, 0x50, 0x0e, 0x28,
128
	0x0b, 0x00, 0x00, 0x00, 0x02, 0x02, 0xc0, 0xd4,
129
	0x01, 0x00, 0x04, 0x00, 0x08, 0x0f, 0x86
130
};
131
132
static unsigned char scan_sequence[17] = {
133
	0x43, 0x69, 0x61, 0x6f, 0x00, 0xff, 0x08, 0x28,
134
	0x05, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0xff,
135
	0xff
136
};
137
138
static unsigned char termination_request = 0x01;
139
140
struct libthinkfinger_s {
141
	struct sigaction sigint_action;
142
	struct sigaction sigint_action_old;
143
	struct usb_dev_handle *usb_dev_handle;
144
	const char *file;
145
	int fd;
146
147
	pthread_mutex_t usb_deinit_mutex;
148
	libthinkfinger_task task;
149
	_Bool task_running;
150
	_Bool result_pending;
151
	unsigned char next_sequence;
152
153
	libthinkfinger_state state;
154
	libthinkfinger_state_cb cb;
155
	void *cb_data;
156
};
157
158
static void sigint_handler (int unused, siginfo_t *sinfo, void *data) {
159
	termination_request = 0x00;
160
	return;
161
}
162
163
static int _libthinkfinger_set_sigint (libthinkfinger *tf)
164
{
165
	int retval;
166
	
167
	tf->sigint_action.sa_sigaction = &sigint_handler;
168
	retval = sigaction (SIGINT, &tf->sigint_action, &tf->sigint_action_old);
169
170
	return retval;
171
}
172
173
static int _libthinkfinger_restore_sigint (libthinkfinger *tf)
174
{
175
	int retval = 0;
176
177
	retval = sigaction(SIGINT, &tf->sigint_action_old, NULL);
178
179
	return retval;
180
}
181
182
static _Bool _libthinkfinger_result_pending (libthinkfinger *tf)
183
{
184
	return tf->result_pending;
185
}
186
187
static void _libthinkfinger_set_result_pending (libthinkfinger *tf, _Bool pending)
188
{
189
	tf->result_pending = pending;
190
}
191
192
static void _libthinkfinger_task_start (libthinkfinger *tf, libthinkfinger_task task)
193
{
194
	tf->task = task;
195
	tf->state = TF_STATE_INITIAL;
196
	tf->task_running = true;
197
}
198
199
static void _libthinkfinger_task_stop (libthinkfinger *tf)
200
{
201
	tf->task_running = false;
202
	tf->task = TF_TASK_IDLE;
203
}
204
205
static _Bool _libthinkfinger_task_running (libthinkfinger *tf)
206
{
207
	return tf->task_running;
208
}
209
210
static libthinkfinger_result _libthinkfinger_get_result (libthinkfinger_state state)
211
{
212
	libthinkfinger_result retval;
213
	switch (state) {
214
		case TF_STATE_ACQUIRE_SUCCESS:
215
			retval = TF_RESULT_ACQUIRE_SUCCESS;
216
			break;
217
		case TF_STATE_ACQUIRE_FAILED:
218
			retval = TF_RESULT_ACQUIRE_FAILED;
219
			break;
220
		case TF_STATE_VERIFY_SUCCESS:
221
			retval = TF_RESULT_VERIFY_SUCCESS;
222
			break;
223
		case TF_STATE_VERIFY_FAILED:
224
			retval = TF_RESULT_VERIFY_FAILED;
225
			break;
226
		case TF_STATE_OPEN_FAILED:
227
			retval = TF_RESULT_OPEN_FAILED;
228
			break;
229
		case TF_STATE_SIGINT:
230
			retval = TF_RESULT_SIGINT;
231
			break;
232
		case TF_STATE_USB_ERROR:
233
			retval = TF_RESULT_USB_ERROR;
234
			break;
235
		case TF_STATE_COMM_FAILED:
236
			retval = TF_RESULT_COMM_FAILED;
237
			break;
238
		default:
239
			retval = TF_RESULT_UNDEFINED;
240
			break;
241
	}
242
243
	return retval;
244
}
245
246
#ifdef USB_DEBUG
247
static void usb_dump (const char *func, unsigned char *bytes, int req_size, int size)
248
{
249
	if (size >= 0) {
250
		fprintf (stderr, "\n%s\t(0x%x/0x%x): ", func, req_size, size);
251
		while (size-- > 0) {
252
			fprintf(stderr, "%2.2x", *bytes);
253
			bytes++;
254
		}
255
		fprintf (stderr, "\n");
256
	} else
257
		fprintf (stderr, "Error: %s (%i)\n", func, size);
258
259
	return;
260
}
261
#endif
262
263
static int _libthinkfinger_usb_hello (struct usb_dev_handle *handle)
264
{
265
	int retval = -1;
266
	char dummy[] = "\x10";
267
268
	/* SET_CONFIGURATION 1 -- should not be relevant */
269
	retval = usb_control_msg (handle,	 // usb_dev_handle *dev
270
				   0x00000000,	 // int requesttype
271
				   0x00000009,	 // int request
272
				   0x001,	 // int value
273
				   0x000,	 // int index
274
				   dummy,	 // char *bytes
275
				   0x00000000,	 // int size
276
				   USB_TIMEOUT); // int timeout
277
	if (retval < 0)
278
		goto out;
279
	retval = usb_control_msg (handle,	 // usb_dev_handle *dev
280
				   0x00000040,	 // int requesttype
281
				   0x0000000c,	 // int request
282
				   0x100,	 // int value
283
				   0x400,	 // int index
284
				   dummy,	 // char *bytes
285
				   0x00000001,	 // int size
286
				   USB_TIMEOUT); // int timeout
287
288
out:
289
	return retval;
290
}
291
292
static int _libthinkfinger_usb_write (libthinkfinger *tf, char *bytes, int size) {
293
	int usb_retval = -1;
294
295
	if (tf->usb_dev_handle == NULL) {
296
#ifdef USB_DEBUG
297
		fprintf (stderr, "_libthinkfinger_usb_write error: USB handle is NULL.\n");
298
#endif
299
		goto out;
300
	}
301
302
	usb_retval = usb_bulk_write (tf->usb_dev_handle, USB_WR_EP, bytes, size, USB_TIMEOUT);
303
	if (usb_retval >= 0 && usb_retval != size)
304
		fprintf (stderr, "Warning: usb_bulk_write expected to write 0x%x (wrote 0x%x bytes).\n",
305
			 size, usb_retval);
306
307
#ifdef USB_DEBUG
308
	usb_dump ("usb_bulk_write", (unsigned char*) bytes, size, usb_retval);
309
#endif
310
out:
311
	return usb_retval;
312
}
313
314
static int _libthinkfinger_usb_read (libthinkfinger *tf, char *bytes, int size) {
315
	int usb_retval = -1;
316
317
	if (tf->usb_dev_handle == NULL) {
318
#ifdef USB_DEBUG
319
		fprintf (stderr, "_libthinkfinger_usb_read error: USB handle is NULL.\n");
320
#endif
321
		goto out;
322
	}
323
324
	usb_retval = usb_bulk_read (tf->usb_dev_handle, USB_RD_EP, bytes, size, USB_TIMEOUT);
325
	if (usb_retval >= 0 && usb_retval != size)
326
		fprintf (stderr, "Warning: usb_bulk_read expected to read 0x%x (read 0x%x bytes).\n",
327
			 size, usb_retval);
328
#ifdef USB_DEBUG
329
	usb_dump ("usb_bulk_read", (unsigned char*) bytes, size, usb_retval);
330
#endif
331
out:
332
	return usb_retval;
333
}
334
335
static void _libthinkfinger_usb_flush (libthinkfinger *tf)
336
{
337
	char buf[64];
338
339
	_libthinkfinger_usb_read (tf, buf, DEFAULT_BULK_SIZE);
340
341
	return;
342
}
343
344
static struct usb_device *_libthinkfinger_usb_device_find (void)
345
{
346
	struct usb_bus *usb_bus;
347
	struct usb_device *dev = NULL;
348
349
	usb_init ();
350
	usb_find_busses ();
351
	usb_find_devices ();
352
353
	/* TODO: Support systems with two fingerprint readers */
354
	for (usb_bus = usb_busses; usb_bus; usb_bus = usb_bus->next) {
355
		for (dev = usb_bus->devices; dev; dev = dev->next) {
356
			if ((dev->descriptor.idVendor == USB_VENDOR_ID) &&
357
			    (dev->descriptor.idProduct == USB_PRODUCT_ID)) {
358
				goto out;
359
			}
360
		}
361
	}
362
out:
363
	return dev;
364
}
365
366
static void _libthinkfinger_usb_deinit_lock (libthinkfinger *tf)
367
{
368
	if (pthread_mutex_lock (&tf->usb_deinit_mutex) < 0)
369
		fprintf (stderr, "pthread_mutex_lock failed: (%s).\n", strerror (errno));
370
	return;
371
}
372
373
static void _libthinkfinger_usb_deinit_unlock (libthinkfinger *tf)
374
{
375
	if (pthread_mutex_unlock (&tf->usb_deinit_mutex) < 0)
376
		fprintf (stderr, "pthread_mutex_unlock failed: (%s).\n", strerror (errno));
377
	return;
378
}
379
380
static void _libthinkfinger_usb_deinit (libthinkfinger *tf)
381
{
382
	int usb_retval;
383
384
	_libthinkfinger_usb_deinit_lock (tf);
385
	if (tf->usb_dev_handle == NULL) {
386
		goto out;
387
	}
388
389
	while (_libthinkfinger_task_running (tf) == true) {
390
		termination_request = 0x00;
391
		usleep (50000);
392
	}
393
394
	usb_retval = _libthinkfinger_usb_write (tf, deinit, sizeof(deinit));
395
	if (usb_retval < 0 && usb_retval != -ETIMEDOUT)
396
		goto usb_close;
397
	 _libthinkfinger_usb_flush (tf);
398
399
usb_close:
400
	usb_release_interface (tf->usb_dev_handle, 0);
401
	usb_close (tf->usb_dev_handle);
402
	tf->usb_dev_handle = NULL;
403
out:
404
	_libthinkfinger_usb_deinit_unlock (tf);
405
	return;
406
}
407
408
static libthinkfinger_init_status _libthinkfinger_usb_init (libthinkfinger *tf)
409
{
410
	libthinkfinger_init_status retval = TF_INIT_UNDEFINED;
411
	struct usb_device *usb_dev;
412
413
	usb_dev = _libthinkfinger_usb_device_find ();
414
	if (usb_dev == NULL) {
415
#ifdef USB_DEBUG
416
		fprintf (stderr, "USB error (device not found).\n");
417
#endif
418
		retval = TF_INIT_USB_DEVICE_NOT_FOUND;
419
		goto out;
420
	}
421
422
	tf->usb_dev_handle = usb_open (usb_dev);
423
	if (tf->usb_dev_handle == NULL) {
424
#ifdef USB_DEBUG
425
		fprintf (stderr, "USB error (did not get handle).\n");
426
#endif
427
		retval = TF_INIT_USB_OPEN_FAILED;
428
		goto out;
429
	}
430
431
	if (usb_claim_interface (tf->usb_dev_handle, 0) < 0) {
432
#ifdef USB_DEBUG
433
		fprintf (stderr, "USB error (%s).\n", usb_strerror ());
434
#endif
435
		retval = TF_INIT_USB_CLAIM_FAILED;
436
		goto out;
437
	}
438
439
	if (_libthinkfinger_usb_hello (tf->usb_dev_handle) < 0) {
440
#ifdef USB_DEBUG
441
		fprintf (stderr, "USB error (sending hello failed).\n");
442
#endif
443
		retval = TF_INIT_USB_HELLO_FAILED;
444
		goto out;
445
	}
446
447
	retval = TF_INIT_USB_INIT_SUCCESS;
448
out:
449
	return retval;
450
}
451
452
static void _libthinkfinger_parse_scan_reply (libthinkfinger *tf, unsigned char *inbuf)
453
{
454
	if (tf == NULL) {
455
		fprintf (stderr, "Error: libthinkfinger not properly initialized.\n");
456
		goto out;
457
	}
458
459
	switch (inbuf[18]) {
460
		case 0x0c:
461
			tf->state = TF_STATE_SWIPE_0;
462
			break;
463
		case 0x0d:
464
		case 0x0e:
465
			switch (inbuf[18]-0x0c) {
466
				case 0x01:
467
					tf->state = TF_STATE_SWIPE_1;
468
					break;
469
				case 0x02:
470
					tf->state = TF_STATE_SWIPE_2;
471
					break;
472
				default:
473
					break;
474
			}
475
			break;
476
		case 0x20:
477
			tf->state = TF_STATE_SWIPE_SUCCESS;
478
			break;
479
		case 0x00:
480
			tf->state = TF_STATE_ENROLL_SUCCESS;
481
			break;
482
		case 0x1c:
483
		case 0x1e:
484
		case 0x24:
485
		case 0x0b:
486
			tf->state = TF_STATE_SWIPE_FAILED;
487
			break;
488
		default:
489
#ifdef LIBTHINKFINGER_DEBUG
490
			fprintf (stderr, "Unknown state 0x%x\n", inbuf[18]);
491
#endif
492
			break;
493
	}
494
495
out:
496
	return;
497
}
498
499
static int _libthinkfinger_store_fingerprint (libthinkfinger *tf, unsigned char *data)
500
{
501
	char inbuf[1024];
502
	int retval = -1;
503
	int usb_retval;
504
	int len;
505
506
	if ((tf == NULL) || (tf->fd < 0)) {
507
		fprintf (stderr, "Error: libthinkfinger not properly initialized.\n");
508
		goto out;
509
	}
510
511
	if (write (tf->fd, data+18, 0x40-18) < 0) {
512
		fprintf (stderr, "Error: %s.\n", strerror (errno));
513
		goto out;
514
	}
515
516
	len = ((data[5] & 0x0f) << 8) + data[6] - 0x37;
517
	usb_retval = _libthinkfinger_usb_read (tf, inbuf, len);
518
	if (usb_retval != len)
519
		fprintf (stderr, "Warning: Expected 0x%x bytes but read 0x%x).\n", len, usb_retval);
520
	if (write (tf->fd, inbuf, usb_retval) < 0)
521
		fprintf (stderr, "Error: %s.\n", strerror (errno));
522
	else
523
		retval = 0;
524
525
	/* reset termination_request */
526
	termination_request = 0x01;
527
out:
528
	return retval;
529
}
530
531
/* returns 1 if it understood the packet */
532
static int _libthinkfinger_parse (libthinkfinger *tf, unsigned char *inbuf)
533
{
534
	int retval = -1;
535
536
	libthinkfinger_state state = tf->state;
537
	const char fingerprint_is[] = {
538
		0x00, 0x00, 0x00, 0x02, 0x12, 0xff, 0xff, 0xff,
539
		0xff
540
	};
541
542
	if (tf == NULL) {
543
		fprintf (stderr, "Error: libthinkfinger not properly initialized.\n");
544
		goto out;
545
	}
546
547
	_libthinkfinger_set_result_pending (tf, false);
548
549
	switch (inbuf[7]) {
550
		case 0x28:
551
			tf->next_sequence = (inbuf[5] + 0x20) & 0x00ff;
552
			if (tf->state == TF_STATE_ENROLL_SUCCESS && !memcmp(inbuf+9, fingerprint_is, 9)) {
553
				retval = _libthinkfinger_store_fingerprint (tf, inbuf);
554
				if (retval < 0)
555
					tf->state = TF_STATE_ACQUIRE_FAILED;
556
				else
557
					tf->state = TF_STATE_ACQUIRE_SUCCESS;
558
				_libthinkfinger_task_stop (tf);
559
				break;
560
			}
561
			switch (inbuf[6]) {
562
				case 0x07:
563
					tf->state = TF_STATE_COMM_FAILED;
564
					_libthinkfinger_task_stop (tf);
565
					break;
566
				case 0x0b:
567
					tf->state = TF_STATE_VERIFY_FAILED;
568
					_libthinkfinger_task_stop (tf);
569
					break;
570
				case 0x13:
571
					switch (inbuf[14]) {
572
						case 0x00:
573
							tf->state = TF_STATE_VERIFY_FAILED;
574
							break;
575
						case 0x01:
576
							tf->state = TF_STATE_VERIFY_SUCCESS;
577
							break;
578
					}
579
					_libthinkfinger_task_stop (tf);
580
					break;
581
				case 0x14:
582
					_libthinkfinger_parse_scan_reply (tf, inbuf);
583
					break;
584
				default:
585
					retval = 0;
586
					break;
587
			}
588
			retval = 1;
589
			break;
590
		case 0xa1:
591
			/* device is busy, result pending */
592
			_libthinkfinger_set_result_pending (tf, true);
593
			retval = 1;
594
		default:
595
			retval = 0;
596
	}
597
598
	if (tf->state != state && tf->cb != NULL)
599
		tf->cb (tf->state, tf->cb_data);
600
out:
601
	return retval;
602
}
603
604
#define SILENT 1
605
#define PARSE 2
606
607
static void _libthinkfinger_ask_scanner_raw (libthinkfinger *tf, int flags, char *ctrldata, int read_size, int write_size)
608
{
609
	int usb_retval;
610
	unsigned char inbuf[10240];
611
612
	if (tf == NULL) {
613
		fprintf (stderr, "Error: libthinkfinger not properly initialized.\n");
614
		goto out;
615
	}
616
617
	if (_libthinkfinger_task_running (tf) == false)
618
		goto out;
619
620
	_libthinkfinger_set_result_pending (tf, true);
621
	while (_libthinkfinger_result_pending (tf) == true) {
622
		usb_retval = _libthinkfinger_usb_read (tf, (char *)&inbuf, read_size);
623
		if (usb_retval < 0 && usb_retval != -ETIMEDOUT)
624
			goto out_usb_error;
625
626
		if (flags & PARSE) {
627
			if (_libthinkfinger_parse (tf, inbuf))
628
				flags |= SILENT;
629
			if (_libthinkfinger_task_running (tf) == false)
630
				goto out_result;
631
			if (_libthinkfinger_result_pending (tf) == true) {
632
				_libthinkfinger_usb_write (tf, (char *)device_busy, sizeof(device_busy));
633
				if (usb_retval < 0 && usb_retval != -ETIMEDOUT)
634
					goto out_usb_error;
635
			}
636
		} else {
637
			_libthinkfinger_set_result_pending (tf, false);
638
		}
639
	}
640
641
	if (termination_request == 0x00) {
642
		ctrldata[14] = termination_request;
643
		tf->state = TF_STATE_SIGINT;
644
	}
645
646
	*((short *) (ctrldata+write_size-2)) = udf_crc ((u8*)&(ctrldata[4]), write_size-6, 0);
647
	usb_retval = _libthinkfinger_usb_write (tf, (char *)ctrldata, write_size);
648
	if (usb_retval < 0 && usb_retval != -ETIMEDOUT)
649
		goto out_usb_error;
650
	else {
651
		goto out_result;
652
	}
653
654
out_usb_error:
655
	tf->state = TF_STATE_USB_ERROR;
656
657
out_result:
658
	switch (tf->state) {
659
		case TF_STATE_ACQUIRE_SUCCESS:
660
		case TF_STATE_ACQUIRE_FAILED:
661
		case TF_STATE_VERIFY_SUCCESS:
662
		case TF_STATE_VERIFY_FAILED:
663
		case TF_STATE_SIGINT:
664
		case TF_STATE_USB_ERROR:
665
		case TF_STATE_COMM_FAILED: {
666
			_libthinkfinger_task_stop (tf);
667
			break;
668
		}
669
		default:
670
			break;
671
	}
672
673
out:
674
675
	return;
676
}
677
678
static libthinkfinger_init_status _libthinkfinger_init (libthinkfinger *tf)
679
{
680
	libthinkfinger_init_status retval = TF_INIT_UNDEFINED;
681
	int i = 0;
682
683
	retval = _libthinkfinger_usb_init (tf);
684
	if (retval != TF_INIT_USB_INIT_SUCCESS)
685
		goto out;
686
687
	_libthinkfinger_task_start (tf, TF_TASK_INIT);
688
	do {
689
		_libthinkfinger_ask_scanner_raw (tf, SILENT, init[i].data, DEFAULT_BULK_SIZE, init[i].len);
690
	} while (init[++i].data);
691
	_libthinkfinger_usb_flush (tf);
692
	_libthinkfinger_ask_scanner_raw (tf, SILENT, (char *)&init_end, 0x34, sizeof(init_end));
693
	_libthinkfinger_task_stop (tf);
694
695
	retval = TF_INIT_SUCCESS;
696
out:
697
	return retval;
698
}
699
700
static void _libthinkfinger_scan (libthinkfinger *tf) {
701
	tf->next_sequence = INITIAL_SEQUENCE;
702
	_libthinkfinger_set_sigint (tf);
703
	while (_libthinkfinger_task_running (tf)) {
704
		scan_sequence[5] = tf->next_sequence;
705
		_libthinkfinger_ask_scanner_raw (tf, PARSE, (char *)scan_sequence, DEFAULT_BULK_SIZE, sizeof (scan_sequence));
706
	}
707
708
	if (termination_request == 0x00) {
709
		_libthinkfinger_usb_flush (tf);
710
		goto out;
711
	}
712
713
out:
714
	_libthinkfinger_restore_sigint (tf);
715
	return;
716
}
717
718
static void _libthinkfinger_verify_run (libthinkfinger *tf)
719
{
720
	int header = 13*3-1;
721
	int filesize;
722
723
	tf->fd = open (tf->file, O_RDONLY | O_NOFOLLOW);
724
	if (tf->fd < 0) {
725
		fprintf (stderr, "Error: %s.\n", strerror (errno));
726
		_libthinkfinger_usb_flush (tf);
727
		tf->state = TF_STATE_OPEN_FAILED;
728
		goto out;
729
	}
730
731
	filesize = read (tf->fd, ctrlbuf+header, sizeof(ctrlbuf)-header);
732
	*((short *) (ctrlbuf+8)) = filesize + 28;
733
	ctrlbuf[5] = (filesize+20511) >> 8;
734
	ctrlbuf[6] = (filesize+20511) & 0xff;
735
	ctrlbuf[header+filesize] = 0x4f;
736
	ctrlbuf[header+filesize+1] = 0x47;
737
738
	_libthinkfinger_task_start (tf, TF_TASK_VERIFY);
739
	_libthinkfinger_ask_scanner_raw (tf, SILENT, ctrlbuf, DEFAULT_BULK_SIZE, header+filesize+2);
740
	_libthinkfinger_scan (tf);
741
742
	if (close (tf->fd) == 0)
743
		tf->fd = 0;
744
out:
745
	return;
746
}
747
748
libthinkfinger_result libthinkfinger_verify (libthinkfinger *tf)
749
{
750
	libthinkfinger_result retval = TF_RESULT_UNDEFINED;
751
752
	if (tf == NULL) {
753
		fprintf (stderr, "Error: libthinkfinger not properly initialized.\n");
754
		goto out;
755
	}
756
	
757
	_libthinkfinger_init (tf);
758
	_libthinkfinger_verify_run (tf);
759
	retval = _libthinkfinger_get_result (tf->state);
760
out:
761
	return retval;
762
}
763
764
static void _libthinkfinger_acquire_run (libthinkfinger *tf)
765
{
766
	tf->fd = open (tf->file, O_RDWR | O_CREAT | O_NOFOLLOW, 0600);
767
	if (tf->fd < 0) {
768
		fprintf (stderr, "Error: %s.\n", strerror (errno));
769
		_libthinkfinger_usb_flush (tf);
770
		tf->state = TF_STATE_OPEN_FAILED;
771
		goto out;
772
	}
773
774
	_libthinkfinger_task_start (tf, TF_TASK_ACQUIRE);
775
	_libthinkfinger_ask_scanner_raw (tf, SILENT, enroll_init, DEFAULT_BULK_SIZE, sizeof(enroll_init));
776
	_libthinkfinger_scan (tf);
777
778
	if (close (tf->fd) == 0)
779
		tf->fd = 0;
780
out:
781
	return;
782
}
783
784
libthinkfinger_result libthinkfinger_acquire (libthinkfinger *tf)
785
{
786
	libthinkfinger_result retval = TF_RESULT_UNDEFINED;
787
788
	if (tf == NULL) {
789
		fprintf (stderr, "Error: libthinkfinger not properly initialized.\n");
790
		goto out;
791
	}
792
793
	_libthinkfinger_init (tf);
794
	_libthinkfinger_acquire_run (tf);
795
	retval = _libthinkfinger_get_result (tf->state);
796
out:
797
	return retval;
798
}
799
800
int libthinkfinger_set_file (libthinkfinger *tf, const char *file)
801
{
802
	int retval = -1;
803
804
	if (tf == NULL) {
805
		fprintf (stderr, "Error: libthinkfinger not properly initialized.\n");
806
		goto out;
807
	}
808
809
	tf->file = file;
810
	retval = 0;
811
out:
812
	return retval;
813
}
814
815
int libthinkfinger_set_callback (libthinkfinger *tf, libthinkfinger_state_cb cb, void *cb_data)
816
{
817
	int retval = -1;
818
819
	if (tf == NULL) {
820
		fprintf (stderr, "Error: libthinkfinger not properly initialized.\n");
821
		goto out;
822
	}
823
824
	tf->cb = cb;
825
	tf->cb_data = cb_data;
826
	retval = 0;
827
out:
828
	return retval;
829
}
830
831
libthinkfinger *libthinkfinger_new (libthinkfinger_init_status *init_status)
832
{
833
	libthinkfinger *tf = NULL;
834
835
	tf = calloc(1, sizeof(libthinkfinger));
836
	if (tf == NULL) {
837
		/* failed to allocate memory */
838
		*init_status = TF_INIT_NO_MEMORY;
839
		goto out;
840
	}
841
842
843
	tf->usb_dev_handle = NULL;
844
	tf->file = NULL;
845
	tf->fd = -1;
846
	tf->task = TF_TASK_UNDEFINED;
847
	tf->task_running = false;
848
	tf->state = TF_STATE_INITIAL;
849
	tf->cb = NULL;
850
	tf->cb_data = NULL;
851
	if (pthread_mutex_init (&tf->usb_deinit_mutex, NULL) < 0)
852
		fprintf (stderr, "pthread_mutex_init failed: (%s).\n", strerror (errno));
853
854
	if ((*init_status = _libthinkfinger_init (tf)) != TF_INIT_SUCCESS)
855
		goto out;
856
857
	_libthinkfinger_usb_flush (tf);
858
	_libthinkfinger_usb_deinit (tf);
859
860
	*init_status = TF_INIT_SUCCESS;
861
out:
862
	return tf;
863
}
864
865
void libthinkfinger_free (libthinkfinger *tf)
866
{
867
	if (tf == NULL) {
868
		fprintf (stderr, "Error: libthinkfinger not properly initialized.\n");
869
		goto out;
870
	}
871
872
	_libthinkfinger_usb_deinit (tf);
873
874
	if (tf->fd)
875
		close (tf->fd);
876
877
	free(tf);
878
out:
879
	return;
880
}
881
882
/** @mainpage libthinkfinger
883
 *
884
 * \section sec_intro Introduction
885
 *
886
 * ThinkFinger is a driver for the SGS Thomson Microelectronics fingerprint reader
887
 * found in most IBM/Lenovo ThinkPads.
888
 */
889