~ubuntu-branches/ubuntu/trusty/argyll/trusty-proposed

« back to all changes in this revision

Viewing changes to libusb1/examples/dpfp_threaded.c

  • Committer: Package Import Robot
  • Author(s): Artur Rona
  • Date: 2014-02-12 00:35:39 UTC
  • mfrom: (13.1.24 sid)
  • Revision ID: package-import@ubuntu.com-20140212003539-24tautzlitsiz61w
Tags: 1.5.1-5ubuntu1
* Merge from Debian unstable. (LP: #1275572) Remaining changes:
  - debian/control:
    + Build-depend on libtiff-dev rather than libtiff4-dev.
  - debian/control, debian/patches/06_fix_udev_rule.patch:
    + Fix udev rules to actually work; ENV{ACL_MANAGE} has
      stopped working ages ago, and with logind it's now the
      "uaccess" tag. Dropping also consolekit from Recommends.
  - debian/patches/drop-usb-db.patch:
    + Use hwdb builtin, instead of the obsolete usb-db
      in the udev rules.
* debian/patches/05_ftbfs-underlinkage.diff:
  - Dropped change, no needed anymore.
* Refresh the patches.

Show diffs side-by-side

added added

removed removed

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