2 * UPEK TouchStrip driver for libfprint
3 * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
5 * Based in part on libthinkfinger:
6 * Copyright (C) 2006-2007 Timo Hoenig <thoenig@suse.de>
7 * Copyright (C) 2006 Pavel Machek <pavel@suse.cz>
9 * LGPL CRC code copied from GStreamer-0.10.10:
10 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
11 * Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the
25 * Free Software Foundation, Inc.,
26 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #define FP_COMPONENT "upekts"
36 #include <fp_internal.h>
38 #define EP_IN (1 | USB_ENDPOINT_IN)
39 #define EP_OUT (2 | USB_ENDPOINT_OUT)
46 static const uint16_t crc_table
[256] = {
47 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
48 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
49 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
50 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
51 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
52 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
53 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
54 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
55 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
56 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
57 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
58 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
59 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
60 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
61 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
62 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
63 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
64 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
65 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
66 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
67 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
68 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
69 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
70 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
71 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
72 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
73 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
74 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
75 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
76 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
77 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
78 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
81 static uint16_t udf_crc(unsigned char *buffer
, size_t size
)
85 crc
= (uint16_t) ((crc
<< 8) ^
86 crc_table
[((crc
>> 8) & 0x00ff) ^ *buffer
++]);
93 * Messages to and from the device have the same format.
96 * 'C' 'i' 'a' 'o' A B L <DATA> C1 C2
98 * Ciao prefixes all messages. L is the length of the data, <DATA> is L bytes
99 * long. C1 and C2 are the UDF-CRC16 for the whole message minus the Ciao
102 * When the device wants to command the driver to do something, it sends
103 * a message where B=0 and A!=0. The A value indicates the type of command.
104 * If the system is expected to respond to the command, it sends a message back
105 * with B=0 and A incremented.
107 * When the driver sends a command to the device, A=0 and B is used as a
108 * sequence counter. It starts at 0, increments by 0x10 on each command, and
110 * After each command is sent, the device responds with another message
111 * indicating completion of the command including any data that was requested.
112 * This message has the same A and B values.
114 * When the driver is sending commands as above, and when the device is
115 * responding, the <DATA> seems to follow this structure:
117 * 28 L 0 0 0 S <INNERDATA>
119 * Where the length of <INNERDATA> is L-3, and S is some kind of subcommand
120 * code. In the device's response to a command, the subcommand code will be
123 * After deducing and documenting the above, I found a few places where the
124 * above doesn't hold true. Those are marked with FIXME's below.
127 #define CMD_SEQ_INCREMENT 0x10
129 static int send_cmd(struct fp_dev
*dev
, unsigned char seq_a
,
130 unsigned char seq_b
, unsigned char *data
, uint8_t len
)
135 /* 9 bytes extra for: 4 byte 'Ciao', 1 byte A, 1 byte B, 1 byte length,
137 size_t urblen
= len
+ 9;
140 if (!data
&& len
> 0) {
141 fp_err("len>0 but no data?");
145 buf
= g_malloc(urblen
);
148 strncpy(buf
, "Ciao", 4);
155 memcpy(buf
+ 7, data
, len
);
158 crc
= cpu_to_be16(udf_crc(buf
+ 4, urblen
- 6));
159 buf
[urblen
- 2] = crc
>> 8;
160 buf
[urblen
- 1] = crc
& 0xff;
162 r
= usb_bulk_write(dev
->udev
, EP_OUT
, buf
, urblen
, TIMEOUT
);
165 fp_err("cmd write failed, code %d", r
);
167 } else if ((unsigned int) r
< urblen
) {
168 fp_err("cmd write too short (%d/%d)", r
, urblen
);
175 static int send_cmd28(struct fp_dev
*dev
, unsigned char subcmd
,
176 unsigned char *data
, uint8_t innerlen
)
178 size_t len
= innerlen
+ 6;
179 unsigned char *buf
= g_malloc0(len
);
180 struct upekts_dev
*upekdev
= dev
->priv
;
181 uint8_t seq
= upekdev
->seq
+ CMD_SEQ_INCREMENT
;
184 fp_dbg("seq=%02x subcmd=%02x with %d bytes of data", seq
, subcmd
, innerlen
);
187 buf
[1] = innerlen
+ 3;
189 memcpy(buf
+ 6, data
, innerlen
);
191 r
= send_cmd(dev
, 0, seq
, buf
, len
);
199 static int send_cmdresponse(struct fp_dev
*dev
, unsigned char seq
,
200 unsigned char *data
, uint8_t len
)
202 fp_dbg("seq=%02x len=%d", seq
, len
);
203 return send_cmd(dev
, seq
, 0, data
, len
);
206 static unsigned char *__read_msg(struct fp_dev
*dev
, size_t *data_len
)
208 #define MSG_READ_BUF_SIZE 0x40
209 #define MAX_DATA_IN_READ_BUF (MSG_READ_BUF_SIZE - 9)
210 unsigned char *buf
= g_malloc(MSG_READ_BUF_SIZE
);
211 size_t buf_size
= MSG_READ_BUF_SIZE
;
212 uint16_t computed_crc
, msg_crc
;
216 r
= usb_bulk_read(dev
->udev
, EP_IN
, buf
, buf_size
, TIMEOUT
);
218 fp_err("msg read failed, code %d", r
);
221 fp_err("msg read too short (%d/%d)", r
, buf_size
);
225 if (strncmp(buf
, "Ciao", 4) != 0) {
226 fp_err("no Ciao for you!!");
232 if (r
!= MSG_READ_BUF_SIZE
&& (len
+ 9) < r
) {
233 /* Check that the length claimed inside the message is in line with
234 * the amount of data that was transferred over USB. */
235 fp_err("msg didn't include enough data, expected=%d recv=%d",
240 /* We use a 64 byte buffer for reading messages. However, sometimes
241 * messages are longer, in which case we have to do another USB bulk read
242 * to read the remainder. This is handled below. */
243 if (len
> MAX_DATA_IN_READ_BUF
) {
244 int needed
= len
- MAX_DATA_IN_READ_BUF
;
245 fp_dbg("didn't fit in buffer, need to extend by %d bytes", needed
);
246 buf
= g_realloc((gpointer
) buf
, MSG_READ_BUF_SIZE
+ needed
);
247 r
= usb_bulk_read(dev
->udev
, EP_IN
, buf
+ MSG_READ_BUF_SIZE
, needed
,
250 fp_err("extended msg read failed, code %d", r
);
252 } else if (r
< needed
) {
253 fp_err("extended msg short read (%d/%d)", r
, needed
);
259 computed_crc
= udf_crc(buf
+ 4, len
+ 3);
260 msg_crc
= le16_to_cpu((buf
[len
+ 8] << 8) | buf
[len
+ 7]);
261 if (computed_crc
!= msg_crc
) {
262 fp_err("CRC failed, got %04x expected %04x", msg_crc
, computed_crc
);
266 *data_len
= buf_size
;
273 enum read_msg_status
{
276 READ_MSG_RESPONSE
= 2,
279 static enum read_msg_status
read_msg(struct fp_dev
*dev
, uint8_t *seq
,
280 unsigned char *subcmd
, unsigned char **data
, size_t *data_len
)
282 #define MSG_READ_BUF_SIZE 0x40
283 #define MAX_DATA_IN_READ_BUF (MSG_READ_BUF_SIZE - 9)
286 unsigned char code_a
;
287 unsigned char code_b
;
289 enum read_msg_status ret
= READ_MSG_ERROR
;
292 buf
= __read_msg(dev
, &buf_size
);
294 return READ_MSG_ERROR
;
299 fp_dbg("A=%02x B=%02x len=%d", code_a
, code_b
, len
);
301 if (code_a
&& !code_b
) {
302 /* device sends command to driver */
303 fp_dbg("cmd %x from device to driver", code_a
);
305 if (code_a
== 0x08) {
306 fp_dbg("device busy, send busy-ack");
307 send_cmdresponse(dev
, 0x09, NULL
, 0);
316 unsigned char *tmp
= g_malloc(len
);
317 memcpy(tmp
, buf
+ 7, len
);
323 } else if (!code_a
) {
324 /* device sends response to a previously executed command */
325 unsigned char *innerbuf
= buf
+ 7;
326 unsigned char _subcmd
;
330 fp_err("cmd response too short (%d)", len
);
333 if (innerbuf
[0] != 0x28) {
334 fp_err("cmd response without 28 byte?");
337 if (innerbuf
[2] || innerbuf
[3] || innerbuf
[4]) {
338 fp_err("non-zero bytes in cmd response");
342 innerlen
= innerbuf
[1] - 3;
343 _subcmd
= innerbuf
[5];
344 fp_dbg("device responds to subcmd %x with %d bytes", _subcmd
, innerlen
);
351 unsigned char *tmp
= g_malloc(innerlen
);
352 memcpy(tmp
, innerbuf
+ 6, innerlen
);
355 *data_len
= innerlen
;
357 ret
= READ_MSG_RESPONSE
;
359 fp_err("don't know how to handle this message");
367 static int read_msg28(struct fp_dev
*dev
, unsigned char subcmd
,
368 unsigned char **data
, size_t *data_len
)
370 struct upekts_dev
*upekdev
= dev
->priv
;
372 unsigned char _subcmd
;
373 enum read_msg_status msgstat
;
375 msgstat
= read_msg(dev
, &_seq
, &_subcmd
, data
, data_len
);
376 if (msgstat
!= READ_MSG_RESPONSE
) {
377 fp_err("expected response, got %d seq=%x", msgstat
, _seq
);
380 if (_subcmd
!= subcmd
) {
381 fp_warn("expected response to subcmd %02x, got response to %02x",
385 if (_seq
!= upekdev
->seq
) {
386 fp_err("expected response to cmd seq=%02x, got response to %02x",
394 static const unsigned char init_resp03
[] = {
395 0x01, 0x00, 0xe8, 0x03, 0x00, 0x00, 0xff, 0x07
397 static const unsigned char init28_08
[] = {
398 0x04, 0x83, 0x00, 0x2c, 0x22, 0x23, 0x97, 0xc9, 0xa7, 0x15, 0xa0, 0x8a,
399 0xab, 0x3c, 0xd0, 0xbf, 0xdb, 0xf3, 0x92, 0x6f, 0xae, 0x3b, 0x1e, 0x44,
402 static const unsigned char init28_0c
[] = {
403 0x04, 0x03, 0x00, 0x00, 0x00
405 static const unsigned char init28_0b
[] = {
406 0x04, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
407 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
408 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
409 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00,
410 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
411 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
412 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a,
413 0x00, 0x64, 0x00, 0xf4, 0x01, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
414 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00
417 static int dev_init(struct fp_dev
*dev
)
419 struct upekts_dev
*upekdev
;
420 unsigned char dummy
= 0x10;
421 enum read_msg_status msgstat
;
425 r
= usb_claim_interface(dev
->udev
, 0);
429 r
= usb_control_msg(dev
->udev
, USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
430 0x0c, 0x100, 0x400, &dummy
, sizeof(dummy
), TIMEOUT
);
434 upekdev
= g_malloc(sizeof(*upekdev
));
435 upekdev
->seq
= 0xf0; /* incremented to 0x00 before first cmd */
437 dev
->nr_enroll_stages
= 3;
439 msgstat
= read_msg(dev
, &seq
, NULL
, NULL
, NULL
);
440 if (msgstat
!= READ_MSG_CMD
) {
441 fp_err("expected command, got %d seq=%x", msgstat
, seq
);
445 fp_err("expected seq=3, got %x", seq
);
449 r
= send_cmdresponse(dev
, ++seq
, (unsigned char *) init_resp03
,
450 sizeof(init_resp03
));
454 msgstat
= read_msg(dev
, &seq
, NULL
, NULL
, NULL
);
455 if (msgstat
!= READ_MSG_CMD
) {
456 fp_err("expected command, got %d seq=%x", msgstat
, seq
);
460 fp_err("expected seq=5, got %x", seq
);
465 r
= send_cmd28(dev
, 0x06, &dummy
, 1);
468 if (read_msg28(dev
, 0x06, NULL
, NULL
) < 0)
472 r
= send_cmd28(dev
, 0x07, &dummy
, 1);
475 if (read_msg28(dev
, 0x07, NULL
, NULL
) < 0)
478 r
= send_cmd28(dev
, 0x08, (unsigned char *) init28_08
,
482 if (read_msg28(dev
, 0x08, NULL
, NULL
) < 0)
485 r
= send_cmd28(dev
, 0x0c, (unsigned char *) init28_0c
,
489 if (read_msg28(dev
, 0x0c, NULL
, NULL
) < 0)
492 r
= send_cmd28(dev
, 0x0b, (unsigned char *) init28_0b
,
496 if (read_msg28(dev
, 0x0b, NULL
, NULL
) < 0)
505 static void dev_exit(struct fp_dev
*dev
)
507 unsigned char dummy
= 0;
509 /* FIXME: either i've misunderstood the message system or this is illegal
510 * here, since we arent responding to anything. */
511 send_cmdresponse(dev
, 0x07, &dummy
, 1);
513 // FIXME should read msg A=01
518 static const unsigned char enroll_init
[] = {
519 0x02, 0xc0, 0xd4, 0x01, 0x00, 0x04, 0x00, 0x08
521 static const unsigned char scan_comp
[] = {
522 0x12, 0xff, 0xff, 0xff, 0xff /* scan completion, prefixes print data */
525 /* used for enrollment and verification */
526 static const unsigned char poll_data
[] = { 0x30, 0x01 };
528 static int enroll(struct fp_dev
*dev
, gboolean initial
,
529 int stage
, struct fp_print_data
**_data
)
538 r
= send_cmd28(dev
, 0x02, (unsigned char *) enroll_init
,
539 sizeof(enroll_init
));
542 /* FIXME: protocol misunderstanding here. device receives response
543 * to subcmd 0 after submitting subcmd 2? */
544 /* actually this is probably a poll response? does the above cmd
545 * include a 30 01 poll somewhere? */
546 if (read_msg28(dev
, 0x00, NULL
, NULL
) < 0)
551 unsigned char status
;
553 r
= send_cmd28(dev
, 0x00, (unsigned char *) poll_data
,
557 if (read_msg28(dev
, 0x00, &data
, &data_len
) < 0)
560 if (data_len
!= 14) {
561 fp_err("received 3001 poll response of %d bytes?", data_len
);
567 fp_dbg("poll result = %02x", status
);
569 /* These codes indicate that we're waiting for a finger scan, so poll
575 /* no news, poll again */
577 result
= FP_ENROLL_PASS
;
579 case 0x1c: /* FIXME what does this one mean? */
580 result
= FP_ENROLL_RETRY
;
582 case 0x0f: /* scan taking too long, remove finger and try again */
583 result
= FP_ENROLL_RETRY_REMOVE_FINGER
;
585 case 0x1e: /* swipe too short */
586 result
= FP_ENROLL_RETRY_TOO_SHORT
;
588 case 0x24: /* finger not centered */
589 result
= FP_ENROLL_RETRY_CENTER_FINGER
;
592 /* finger scanned successfully */
593 /* don't break out immediately, need to look at the next
594 * value to determine if enrollment is complete or not */
599 result
= FP_ENROLL_COMPLETE
;
602 fp_err("unrecognised scan status code %02x", status
);
609 /* FIXME: need to extend protocol research to handle the case when
610 * enrolment fails, e.g. you scan a different finger on each stage */
612 if (result
== FP_ENROLL_COMPLETE
) {
613 struct fp_print_data
*fdata
;
615 r
= send_cmd28(dev
, 0x00, (unsigned char *) poll_data
,
619 /* FIXME: protocol misunderstanding here. device receives response
620 * to subcmd 0 after submitting subcmd 2? */
621 if (read_msg28(dev
, 0x02, &data
, &data_len
) < 0)
624 if (data_len
< sizeof(scan_comp
)) {
625 fp_err("fingerprint data too short (%d bytes)", data_len
);
629 if (memcmp(data
, scan_comp
, sizeof(scan_comp
)) != 0) {
630 fp_err("unrecognised data prefix %x %x %x %x %x",
631 data
[0], data
[1], data
[2], data
[3], data
[4]);
636 fp_err("complete but no data storage!");
637 result
= FP_ENROLL_COMPLETE
;
641 fdata
= fpi_print_data_new(dev
, data_len
- sizeof(scan_comp
));
642 memcpy(fdata
->buffer
, data
+ sizeof(scan_comp
), data_len
- sizeof(scan_comp
));
651 static const unsigned char verify_hdr
[] = {
652 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653 0x00, 0xc0, 0xd4, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
657 static int verify(struct fp_dev
*dev
, struct fp_print_data
*print
)
659 size_t data_len
= sizeof(verify_hdr
) + print
->length
;
662 unsigned char status
;
663 gboolean need_poll
= FALSE
;
664 gboolean done
= FALSE
;
666 if (data_len
> 255) {
667 fp_err("file too long!\n");
671 data
= g_malloc(data_len
);
672 memcpy(data
, verify_hdr
, sizeof(verify_hdr
));
673 memcpy(data
+ sizeof(verify_hdr
), print
->buffer
, print
->length
);
675 r
= send_cmd28(dev
, 0x03, data
, data_len
);
682 r
= send_cmd28(dev
, 0x00, (unsigned char *) poll_data
,
689 if (read_msg28(dev
, 0x00, &data
, &data_len
) < 0)
692 if (data_len
!= 14) {
693 fp_err("received 3001 poll response of %d bytes?", data_len
);
699 fp_dbg("poll result = %02x", status
);
701 /* These codes indicate that we're waiting for a finger scan, so poll
704 case 0x0c: /* no news, poll again */
707 fp_dbg("processing scan for verification");
710 fp_dbg("good image");
713 case 0x1c: /* FIXME what does this one mean? */
716 case 0x0f: /* scan taking too long, remove finger and try again */
717 r
= FP_VERIFY_RETRY_REMOVE_FINGER
;
719 case 0x1e: /* swipe too short */
720 r
= FP_VERIFY_RETRY_TOO_SHORT
;
722 case 0x24: /* finger not centered */
723 r
= FP_VERIFY_RETRY_CENTER_FINGER
;
726 fp_err("unrecognised verify status code %02x", status
);
733 if (status
== 0x00) {
734 /* poll again for verify result */
735 r
= send_cmd28(dev
, 0x00, (unsigned char *) poll_data
,
739 if (read_msg28(dev
, 0x03, &data
, &data_len
) < 0)
742 fp_err("verify result abnormally short!");
746 if (data
[0] != 0x12) {
747 fp_err("unexpected verify header byte %02x", data
[0]);
751 if (data
[1] == 0x00) {
752 r
= FP_VERIFY_NO_MATCH
;
753 } else if (data
[1] == 0x01) {
756 fp_err("unrecognised verify result %02x", data
[1]);
767 static const struct usb_id id_table
[] = {
768 { .vendor
= 0x0483, .product
= 0x2016 },
769 { 0, 0, 0, }, /* terminating entry */
772 const struct fp_driver upekts_driver
= {
773 .name
= FP_COMPONENT
,
774 .full_name
= "UPEK TouchStrip",
775 .id_table
= id_table
,