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

« back to all changes in this revision

Viewing changes to libthinkfinger/libthinkfinger.c

  • Committer: Bazaar Package Importer
  • Author(s): Luca Capello
  • Date: 2007-09-15 14:44:23 UTC
  • Revision ID: james.westby@ubuntu.com-20070915144423-6m2api7re19o2wxo
Tags: upstream-0.3
ImportĀ upstreamĀ versionĀ 0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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