GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/upekts.c
Date: 2025-03-01 04:11:53
Exec Total Coverage
Lines: 15 588 2.6%
Functions: 4 53 7.5%
Branches: 3 161 1.9%

Line Branch Exec Source
1 /*
2 * UPEK TouchStrip driver for libfprint
3 * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
4 *
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>
8 *
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>
12
13 * This library is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as
15 * published by the Free Software Foundation; either version 2.1 of the
16 * License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 * 02110-1301 USA
27 */
28
29 #define FP_COMPONENT "upekts"
30
31 #include "drivers_api.h"
32 #include "upek_proto.h"
33
34 #define EP_IN (1 | FPI_USB_ENDPOINT_IN)
35 #define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
36 #define TIMEOUT 5000
37
38 #define MSG_READ_BUF_SIZE 0x40
39
40 struct _FpiDeviceUpekts
41 {
42 FpDevice parent;
43
44 gboolean enroll_passed;
45 gint enroll_stage;
46 gboolean first_verify_iteration;
47 guint8 seq; /* FIXME: improve/automate seq handling */
48 };
49
50 G_DECLARE_FINAL_TYPE (FpiDeviceUpekts, fpi_device_upekts, FPI,
51 DEVICE_UPEKTS, FpDevice);
52
3/4
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 121 times.
✗ Branch 3 not taken.
387 G_DEFINE_TYPE (FpiDeviceUpekts, fpi_device_upekts, FP_TYPE_DEVICE);
53
54 /*
55 * MESSAGE FORMAT
56 *
57 * Messages to and from the device have the same format.
58 *
59 * Byte-wise:
60 * 'C' 'i' 'a' 'o' A B L <DATA> C1 C2
61 *
62 * Ciao prefixes all messages. The rightmost 4 bits of B become the uppermost
63 * 4 bits of L, and when combined with the lower 8 bits listed as 'L', L is
64 * the length of the data, <DATA> is L bytes long. C1 and C2 are the
65 * UDF-CRC16 for the whole message minus the Ciao prefix.
66 *
67 * When the device wants to command the driver to do something, it sends
68 * a message where B=0 and A!=0. The A value indicates the type of command.
69 * If the system is expected to respond to the command, it sends a message back
70 * with B=0 and A incremented.
71 *
72 * When the driver sends a command to the device, A=0 and B is used as a
73 * sequence counter. It starts at 0, increments by 0x10 on each command, and
74 * wraps around.
75 * After each command is sent, the device responds with another message
76 * indicating completion of the command including any data that was requested.
77 * This message has the same A and B values.
78 *
79 * When the driver is sending commands as above, and when the device is
80 * responding, the <DATA> seems to follow this structure:
81 *
82 * 28 L1 L2 0 0 S <INNERDATA>
83 *
84 * Where the length of <INNERDATA> is L-3, and S is some kind of subcommand
85 * code. L1 is the least significant bits of L, L2 is the most significant. In
86 * the device's response to a command, the subcommand code will be unchanged.
87 *
88 * After deducing and documenting the above, I found a few places where the
89 * above doesn't hold true. Those are marked with FIXME's below.
90 */
91
92 #define CMD_SEQ_INCREMENT 0x10
93
94 static FpiUsbTransfer *
95 alloc_send_cmd_transfer (FpDevice *dev,
96 unsigned char seq_a,
97 unsigned char seq_b,
98 const unsigned char *data,
99 guint16 len)
100 {
101 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
102 guint16 crc;
103 const char *ciao = "Ciao";
104
105 /* 9 bytes extra for: 4 byte 'Ciao', 1 byte A, 1 byte B | lenHI,
106 * 1 byte lenLO, 2 byte CRC */
107 size_t urblen = len + 9;
108
109 if (!data && len > 0)
110 {
111 fp_err ("len>0 but no data?");
112 return NULL;
113 }
114
115 fpi_usb_transfer_fill_bulk (transfer, EP_OUT, urblen);
116
117 /* Write header */
118 memcpy (transfer->buffer, ciao, strlen (ciao));
119 transfer->buffer[4] = seq_a;
120 transfer->buffer[5] = seq_b | ((len & 0xf00) >> 8);
121 transfer->buffer[6] = len & 0x00ff;
122
123 /* Copy data */
124 if (data)
125 memcpy (transfer->buffer + 7, data, len);
126
127 /* Append CRC */
128 crc = udf_crc (transfer->buffer + 4, urblen - 6);
129 transfer->buffer[urblen - 2] = crc & 0xff;
130 transfer->buffer[urblen - 1] = crc >> 8;
131
132 return transfer;
133 }
134
135 static FpiUsbTransfer *
136 alloc_send_cmd28_transfer (FpDevice *dev,
137 unsigned char subcmd,
138 const unsigned char *data,
139 guint16 innerlen)
140 {
141 guint16 _innerlen = innerlen;
142 size_t len = innerlen + 6;
143 unsigned char *buf = g_malloc0 (len);
144 FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev);
145 guint8 seq = upekdev->seq + CMD_SEQ_INCREMENT;
146 FpiUsbTransfer *ret;
147
148 fp_dbg ("seq=%02x subcmd=%02x with %d bytes of data", seq, subcmd, innerlen);
149
150 _innerlen = innerlen + 3;
151 buf[0] = 0x28;
152 buf[1] = _innerlen & 0x00ff;
153 buf[2] = (_innerlen & 0xff00) >> 8;
154 buf[5] = subcmd;
155 memcpy (buf + 6, data, innerlen);
156
157 ret = alloc_send_cmd_transfer (dev, 0, seq, buf, len);
158 upekdev->seq = seq;
159
160 g_free (buf);
161 return ret;
162 }
163
164 static FpiUsbTransfer *
165 alloc_send_cmdresponse_transfer (FpDevice *dev,
166 unsigned char seq,
167 const unsigned char *data,
168 guint8 len)
169 {
170 fp_dbg ("seq=%02x len=%d", seq, len);
171 return alloc_send_cmd_transfer (dev, seq, 0, data, len);
172 }
173
174 enum read_msg_type {
175 READ_MSG_CMD,
176 READ_MSG_RESPONSE,
177 };
178
179 typedef void (*read_msg_cb_fn)(FpDevice *dev,
180 enum read_msg_type type,
181 guint8 seq,
182 unsigned char subcmd,
183 unsigned char *data,
184 size_t data_len,
185 void *user_data,
186 GError *error);
187
188 struct read_msg_data
189 {
190 gssize buflen;
191 guint8 *buffer;
192 read_msg_cb_fn callback;
193 void *user_data;
194 };
195
196 static void __read_msg_async (FpDevice *dev,
197 struct read_msg_data *udata);
198
199 #define READ_MSG_DATA_CB_ERR(dev, udata, error) \
200 (udata)->callback (dev, \
201 READ_MSG_CMD, 0, 0, NULL, 0, (udata)->user_data, error)
202
203 static void
204 busy_ack_sent_cb (FpiUsbTransfer *transfer, FpDevice *device,
205 gpointer user_data, GError *error)
206 {
207 struct read_msg_data *udata = user_data;
208
209 if (error)
210 {
211 READ_MSG_DATA_CB_ERR (device, udata, error);
212 g_free (udata->buffer);
213 g_free (udata);
214 }
215 else
216 {
217 __read_msg_async (device, udata);
218 }
219 }
220
221 static void
222 busy_ack_retry_read (FpDevice *device, struct read_msg_data *udata)
223 {
224 FpiUsbTransfer *transfer;
225
226 transfer = alloc_send_cmdresponse_transfer (device, 0x09, NULL, 0);
227 transfer->short_is_error = TRUE;
228
229 fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, busy_ack_sent_cb, udata);
230 }
231
232 /* Returns 0 if message was handled, 1 if it was a device-busy message, and
233 * negative on error. */
234 static void
235 __handle_incoming_msg (FpDevice *device,
236 struct read_msg_data *udata)
237 {
238 GError *error = NULL;
239 guint8 *buf = udata->buffer;
240 guint16 len;
241 guint16 computed_crc;
242 guint16 msg_crc;
243 unsigned char code_a, code_b;
244
245 g_assert (udata->buflen >= 6);
246 len = ((buf[5] & 0xf) << 8) | buf[6];
247
248 g_assert (udata->buflen >= len + 9);
249 computed_crc = udf_crc (buf + 4, len + 3);
250 msg_crc = (buf[len + 8] << 8) | buf[len + 7];
251
252 if (computed_crc != msg_crc)
253 {
254 fp_err ("CRC failed, got %04x expected %04x", msg_crc, computed_crc);
255 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
256 "CRC check on message failed");
257 goto err;
258 }
259
260 code_a = buf[4];
261 code_b = buf[5] & 0xf0;
262 len = ((buf[5] & 0xf) << 8) | buf[6];
263 fp_dbg ("A=%02x B=%02x len=%d", code_a, code_b, len);
264
265 if (code_a && !code_b)
266 {
267 /* device sends command to driver */
268 fp_dbg ("cmd %x from device to driver", code_a);
269
270 if (code_a == 0x08)
271 {
272 fp_dbg ("device busy, send busy-ack");
273 busy_ack_retry_read (device, udata);
274 return;
275 }
276
277 udata->callback (device, READ_MSG_CMD, code_a, 0, buf + 7, len,
278 udata->user_data, NULL);
279 goto done;
280 }
281 else if (!code_a)
282 {
283 /* device sends response to a previously executed command */
284 unsigned char *innerbuf = buf + 7;
285 unsigned char _subcmd;
286 guint16 innerlen;
287
288 if (len < 6)
289 {
290 fp_warn ("cmd response too short (%d)", len);
291 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
292 "CMD response too short (%d)", len);
293 goto err;
294 }
295 if (innerbuf[0] != 0x28)
296 {
297 fp_warn ("cmd response without 28 byte?");
298 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
299 "CMD response without 0x28 byte");
300 goto err;
301 }
302
303 /* not really sure what these 2 bytes are. on most people's hardware,
304 * these bytes are always 0. However, Alon Bar-Lev's hardware gives
305 * 0xfb 0xff during the READ28_OB initsm stage. so don't error out
306 * if they are different... */
307 if (innerbuf[3] || innerbuf[4])
308 fp_dbg ("non-zero bytes in cmd response");
309
310 innerlen = innerbuf[1] | (innerbuf[2] << 8);
311 innerlen = innerlen - 3;
312 _subcmd = innerbuf[5];
313 fp_dbg ("device responds to subcmd %x with %d bytes", _subcmd, innerlen);
314 udata->callback (device, READ_MSG_RESPONSE, code_b, _subcmd,
315 innerbuf + 6, innerlen, udata->user_data, NULL);
316 goto done;
317 }
318 else
319 {
320 fp_err ("don't know how to handle this message");
321 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
322 "Message cannot be processed");
323 goto err;
324 }
325 g_assert_not_reached ();
326
327 err:
328 READ_MSG_DATA_CB_ERR (device, udata, error);
329 done:
330 g_free (udata->buffer);
331 g_free (udata);
332 }
333
334 static void
335 read_msg_extend_cb (FpiUsbTransfer *transfer, FpDevice *device,
336 gpointer user_data, GError *error)
337 {
338 struct read_msg_data *udata = user_data;
339
340 if (error)
341 {
342 fp_err ("extended msg read failed: %s", error->message);
343 READ_MSG_DATA_CB_ERR (device, udata, error);
344 g_free (udata->buffer);
345 g_free (udata);
346 return;
347 }
348
349 __handle_incoming_msg (device, udata);
350 }
351
352 static void
353 read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
354 gpointer user_data, GError *error)
355 {
356 struct read_msg_data *udata = user_data;
357 guint16 payload_len;
358 gsize packet_len;
359
360 if (error)
361 {
362 fp_err ("async msg read failed: %s", error->message);
363 goto err;
364 }
365 if (transfer->actual_length < 9)
366 {
367 fp_err ("async msg read too short (%d)",
368 (gint) transfer->actual_length);
369 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
370 "Packet from device was too short (%" G_GSSIZE_FORMAT ")",
371 transfer->actual_length);
372 goto err;
373 }
374
375 if (strncmp ((char *) udata->buffer, "Ciao", 4) != 0)
376 {
377 fp_err ("no Ciao for you!!");
378 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
379 "Packet from device had incorrect header");
380 goto err;
381 }
382
383 payload_len = ((udata->buffer[5] & 0xf) << 8) | udata->buffer[6];
384 packet_len = payload_len + 9;
385 if (transfer->actual_length != MSG_READ_BUF_SIZE &&
386 packet_len > transfer->actual_length)
387 {
388 /* Check that the length claimed inside the message is in line with
389 * the amount of data that was transferred over USB. */
390 fp_err ("msg didn't include enough data, expected=%d recv=%d",
391 (gint) packet_len, (gint) transfer->actual_length);
392 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
393 "Packet from device didn't include data");
394 goto err;
395 }
396
397 /* We use a 64 byte buffer for reading messages. However, sometimes
398 * messages are longer, in which case we have to do another USB bulk read
399 * to read the remainder. This is handled below. */
400 if (packet_len > MSG_READ_BUF_SIZE)
401 {
402 int needed = packet_len - MSG_READ_BUF_SIZE;
403 FpiUsbTransfer *etransfer = fpi_usb_transfer_new (device);
404
405 fp_dbg ("didn't fit in buffer, need to extend by %d bytes", needed);
406 udata->buffer = g_realloc ((gpointer) udata->buffer, packet_len);
407 udata->buflen = packet_len;
408
409 fpi_usb_transfer_fill_bulk_full (etransfer, EP_IN,
410 udata->buffer + MSG_READ_BUF_SIZE,
411 needed, NULL);
412 etransfer->short_is_error = TRUE;
413 fpi_usb_transfer_submit (etransfer, TIMEOUT,
414 NULL,
415 read_msg_extend_cb, udata);
416 return;
417 }
418
419 __handle_incoming_msg (device, udata);
420
421 return;
422 err:
423 READ_MSG_DATA_CB_ERR (device, udata, error);
424 g_free (udata->buffer);
425 g_free (udata);
426 }
427
428 static void
429 __read_msg_async (FpDevice *device, struct read_msg_data *udata)
430 {
431 FpiUsbTransfer *transfer = fpi_usb_transfer_new (device);
432
433 if (udata->buflen != MSG_READ_BUF_SIZE)
434 {
435 udata->buffer = g_realloc (udata->buffer, MSG_READ_BUF_SIZE);
436 udata->buflen = MSG_READ_BUF_SIZE;
437 }
438
439 fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, udata->buffer, udata->buflen, NULL);
440 fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, read_msg_cb, udata);
441 }
442
443 static void
444 read_msg_async (FpDevice *dev,
445 read_msg_cb_fn callback,
446 void *user_data)
447 {
448 struct read_msg_data *udata = g_new0 (struct read_msg_data, 1);
449
450 udata->buflen = 0;
451 udata->buffer = NULL;
452 udata->callback = callback;
453 udata->user_data = user_data;
454 __read_msg_async (dev, udata);
455 }
456
457 static const unsigned char init_resp03[] = {
458 0x01, 0x00, 0xe8, 0x03, 0x00, 0x00, 0xff, 0x07
459 };
460 static const unsigned char init28_08[] = {
461 0x04, 0x83, 0x00, 0x2c, 0x22, 0x23, 0x97, 0xc9, 0xa7, 0x15, 0xa0, 0x8a,
462 0xab, 0x3c, 0xd0, 0xbf, 0xdb, 0xf3, 0x92, 0x6f, 0xae, 0x3b, 0x1e, 0x44,
463 0xc4
464 };
465 static const unsigned char init28_0c[] = {
466 0x04, 0x03, 0x00, 0x00, 0x00
467 };
468 static const unsigned char init28_0b[] = {
469 0x04, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
470 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
471 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
472 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00,
473 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
474 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
475 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a,
476 0x00, 0x64, 0x00, 0xf4, 0x01, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
477 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00
478 };
479
480 /* device initialisation state machine */
481
482 enum initsm_states {
483 WRITE_CTRL400 = 0,
484 READ_MSG03,
485 SEND_RESP03,
486 READ_MSG05,
487 SEND28_06,
488 READ28_06,
489 SEND28_07,
490 READ28_07,
491 SEND28_08,
492 READ28_08,
493 SEND28_0C,
494 READ28_0C,
495 SEND28_0B,
496 READ28_0B,
497 INITSM_NUM_STATES,
498 };
499
500 static void
501 initsm_read_msg_response_cb (FpiSsm *ssm,
502 FpDevice *dev,
503 enum read_msg_type type,
504 guint8 seq,
505 unsigned char expect_subcmd,
506 unsigned char subcmd,
507 GError *error)
508 {
509 FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev);
510
511 if (error)
512 {
513 fpi_ssm_mark_failed (ssm, error);
514 }
515 else if (type != READ_MSG_RESPONSE)
516 {
517 fp_err ("expected response, got %d seq=%x in state %d", type, seq,
518 fpi_ssm_get_cur_state (ssm));
519 fpi_ssm_mark_failed (ssm,
520 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
521 "Unexpected message type"));
522 }
523 else if (seq != upekdev->seq)
524 {
525 fp_warn ("expected response to subcmd 0x%02x, got response to %02x in "
526 "state %d", expect_subcmd, subcmd,
527 fpi_ssm_get_cur_state (ssm));
528 fpi_ssm_mark_failed (ssm,
529 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
530 "Unexpected response subcommand"));
531 }
532 else
533 {
534 fpi_ssm_next_state (ssm);
535 }
536 }
537
538 static void
539 read28_0b_cb (FpDevice *dev, enum read_msg_type type,
540 guint8 seq, unsigned char subcmd,
541 unsigned char *data, size_t data_len,
542 void *user_data, GError *error)
543 {
544 initsm_read_msg_response_cb ((FpiSsm *) user_data, dev, type, seq,
545 0x0b, subcmd, error);
546 }
547
548 static void
549 read28_0c_cb (FpDevice *dev, enum read_msg_type type,
550 guint8 seq, unsigned char subcmd,
551 unsigned char *data, size_t data_len,
552 void *user_data, GError *error)
553 {
554 initsm_read_msg_response_cb ((FpiSsm *) user_data, dev, type, seq,
555 0x0c, subcmd, error);
556 }
557
558 static void
559 read28_08_cb (FpDevice *dev, enum read_msg_type type,
560 guint8 seq, unsigned char subcmd,
561 unsigned char *data, size_t data_len,
562 void *user_data, GError *error)
563 {
564 initsm_read_msg_response_cb ((FpiSsm *) user_data, dev, type, seq,
565 0x08, subcmd, error);
566 }
567
568 static void
569 read28_07_cb (FpDevice *dev, enum read_msg_type type,
570 guint8 seq, unsigned char subcmd,
571 unsigned char *data, size_t data_len,
572 void *user_data, GError *error)
573 {
574 initsm_read_msg_response_cb ((FpiSsm *) user_data, dev, type, seq,
575 0x07, subcmd, error);
576 }
577
578 static void
579 read28_06_cb (FpDevice *dev, enum read_msg_type type,
580 guint8 seq, unsigned char subcmd,
581 unsigned char *data, size_t data_len,
582 void *user_data, GError *error)
583 {
584 initsm_read_msg_response_cb ((FpiSsm *) user_data, dev, type, seq,
585 0x06, subcmd, error);
586 }
587
588 static void
589 initsm_read_msg_cmd_cb (FpiSsm *ssm,
590 FpDevice *dev,
591 enum read_msg_type type,
592 guint8 seq,
593 guint8 expected_seq,
594 GError *error)
595 {
596 FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev);
597
598 if (error)
599 {
600 fpi_ssm_mark_failed (ssm, error);
601 return;
602 }
603 else if (type != READ_MSG_CMD)
604 {
605 fp_err ("expected command, got %d seq=%x in state %d", type, seq,
606 fpi_ssm_get_cur_state (ssm));
607 fpi_ssm_mark_failed (ssm,
608 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
609 "Expected command but got response"));
610 return;
611 }
612 upekdev->seq = seq;
613 if (seq != expected_seq)
614 {
615 fp_err ("expected seq=%x, got %x in state %d", expected_seq, seq,
616 fpi_ssm_get_cur_state (ssm));
617 fpi_ssm_mark_failed (ssm,
618 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
619 "Got unexpected sequence number"));
620 return;
621 }
622
623 fpi_ssm_next_state (ssm);
624 }
625
626 static void
627 read_msg05_cb (FpDevice *dev, enum read_msg_type type,
628 guint8 seq, unsigned char subcmd,
629 unsigned char *data, size_t data_len,
630 void *user_data, GError *error)
631 {
632 initsm_read_msg_cmd_cb ((FpiSsm *) user_data, dev, type, 5, seq, error);
633 }
634
635 static void
636 read_msg03_cb (FpDevice *dev, enum read_msg_type type,
637 guint8 seq, unsigned char subcmd,
638 unsigned char *data, size_t data_len,
639 void *user_data, GError *error)
640 {
641 initsm_read_msg_cmd_cb ((FpiSsm *) user_data, dev, type, 3, seq, error);
642 }
643
644 static void
645 initsm_read_msg_handler (FpiSsm *ssm,
646 FpDevice *dev,
647 read_msg_cb_fn callback)
648 {
649 read_msg_async (dev, callback, ssm);
650 }
651
652 static void
653 initsm_send_msg28_handler (FpiSsm *ssm,
654 FpDevice *dev,
655 unsigned char subcmd,
656 const unsigned char *data,
657 guint16 innerlen)
658 {
659 FpiUsbTransfer *transfer;
660
661 transfer = alloc_send_cmd28_transfer (dev, subcmd, data, innerlen);
662 transfer->ssm = ssm;
663 transfer->short_is_error = TRUE;
664 fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
665 }
666
667 static void
668 initsm_run_state (FpiSsm *ssm, FpDevice *dev)
669 {
670 FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev);
671 FpiUsbTransfer *transfer;
672
673 switch (fpi_ssm_get_cur_state (ssm))
674 {
675 case WRITE_CTRL400:;
676 transfer = fpi_usb_transfer_new (dev);
677 fpi_usb_transfer_fill_control (transfer,
678 G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
679 G_USB_DEVICE_REQUEST_TYPE_VENDOR,
680 G_USB_DEVICE_RECIPIENT_DEVICE,
681 0x0c, 0x100, 0x0400, 1);
682 transfer->ssm = ssm;
683 transfer->short_is_error = TRUE;
684 fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
685 break;
686
687 case READ_MSG03:
688 initsm_read_msg_handler (ssm, dev, read_msg03_cb);
689 break;
690
691 case SEND_RESP03:;
692 transfer = alloc_send_cmdresponse_transfer (dev, ++upekdev->seq, init_resp03, sizeof (init_resp03));
693 transfer->ssm = ssm;
694 transfer->short_is_error = TRUE;
695 fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
696 break;
697
698 case READ_MSG05:
699 initsm_read_msg_handler (ssm, dev, read_msg05_cb);
700 break;
701
702 case SEND28_06:;
703 unsigned char dummy28_06 = 0x04;
704 upekdev->seq = 0xf0;
705 initsm_send_msg28_handler (ssm, dev, 0x06, &dummy28_06, 1);
706 break;
707
708 case READ28_06:
709 initsm_read_msg_handler (ssm, dev, read28_06_cb);
710 break;
711
712 case SEND28_07:;
713 unsigned char dummy28_07 = 0x04;
714 initsm_send_msg28_handler (ssm, dev, 0x07, &dummy28_07, 1);
715 break;
716
717 case READ28_07:
718 initsm_read_msg_handler (ssm, dev, read28_07_cb);
719 break;
720
721 case SEND28_08:
722 initsm_send_msg28_handler (ssm, dev, 0x08, init28_08, sizeof (init28_08));
723 break;
724
725 case READ28_08:
726 initsm_read_msg_handler (ssm, dev, read28_08_cb);
727 break;
728
729 case SEND28_0C:
730 initsm_send_msg28_handler (ssm, dev, 0x0c, init28_0c, sizeof (init28_0c));
731 break;
732
733 case READ28_0C:
734 initsm_read_msg_handler (ssm, dev, read28_0c_cb);
735 break;
736
737 case SEND28_0B:
738 initsm_send_msg28_handler (ssm, dev, 0x0b, init28_0b, sizeof (init28_0b));
739 break;
740
741 case READ28_0B:
742 initsm_read_msg_handler (ssm, dev, read28_0b_cb);
743 break;
744 }
745 }
746
747 static FpiSsm *
748 initsm_new (FpDevice *dev)
749 {
750 return fpi_ssm_new (dev, initsm_run_state, INITSM_NUM_STATES);
751 }
752
753 enum deinitsm_states {
754 SEND_RESP07 = 0,
755 READ_MSG01,
756 DEINITSM_NUM_STATES,
757 };
758
759 static void
760 read_msg01_cb (FpDevice *dev, enum read_msg_type type,
761 guint8 seq, unsigned char subcmd,
762 unsigned char *data, size_t data_len,
763 void *user_data, GError *error)
764 {
765 FpiSsm *ssm = user_data;
766 FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev);
767
768 if (error)
769 {
770 fpi_ssm_mark_failed (ssm, error);
771 return;
772 }
773 else if (type != READ_MSG_CMD)
774 {
775 fp_err ("expected command, got %d seq=%x", type, seq);
776 fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
777 "Expected command but got response"));
778 return;
779 }
780 upekdev->seq = seq;
781 if (seq != 1)
782 {
783 fp_err ("expected seq=1, got %x", seq);
784 fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
785 "Got wrong sequence number (%x)",
786 seq));
787 return;
788 }
789
790 fpi_ssm_next_state (ssm);
791 }
792
793 static void
794 deinitsm_state_handler (FpiSsm *ssm, FpDevice *dev)
795 {
796 switch (fpi_ssm_get_cur_state (ssm))
797 {
798 case SEND_RESP07:;
799 FpiUsbTransfer *transfer;
800 unsigned char dummy = 0;
801
802 transfer = alloc_send_cmdresponse_transfer (dev, 0x07, &dummy, 1);
803 transfer->short_is_error = TRUE;
804 transfer->ssm = ssm;
805 fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
806 break;
807
808 case READ_MSG01:;
809 read_msg_async (dev, read_msg01_cb, ssm);
810 break;
811 }
812 }
813
814 static void
815 initsm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
816 {
817 if (error)
818 g_usb_device_release_interface (fpi_device_get_usb_device (dev), 0, 0, NULL);
819
820 fpi_device_open_complete (dev, error);
821 }
822
823 static FpiSsm *
824 deinitsm_new (FpDevice *dev, void *user_data)
825 {
826 return fpi_ssm_new (dev, deinitsm_state_handler, DEINITSM_NUM_STATES);
827 }
828
829 static void
830 dev_init (FpDevice *dev)
831 {
832 FpiSsm *ssm;
833 GError *error = NULL;
834 FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev);
835
836 if (!g_usb_device_claim_interface (fpi_device_get_usb_device (dev), 0, 0, &error))
837 {
838 fpi_device_open_complete (dev, error);
839 return;
840 }
841
842 upekdev->seq = 0xf0; /* incremented to 0x00 before first cmd */
843
844 ssm = fpi_ssm_new (dev, initsm_run_state, INITSM_NUM_STATES);
845 fpi_ssm_start (ssm, initsm_done);
846 }
847
848 static void
849 dev_exit (FpDevice *dev)
850 {
851 GError *error = NULL;
852
853 g_usb_device_release_interface (fpi_device_get_usb_device (dev), 0, 0, &error);
854
855 fpi_device_close_complete (dev, error);
856 }
857
858 static const unsigned char enroll_init[] = {
859 0x02, 0xc0, 0xd4, 0x01, 0x00, 0x04, 0x00, 0x08
860 };
861 static const unsigned char scan_comp[] = {
862 0x12, 0xff, 0xff, 0xff, 0xff /* scan completion, prefixes print data */
863 };
864
865 /* used for enrollment and verification */
866 static const unsigned char poll_data[] = { 0x30, 0x01 };
867
868 enum enroll_start_sm_states {
869 RUN_INITSM = 0,
870 ENROLL_INIT,
871 READ_ENROLL_MSG28,
872 ENROLL_START_NUM_STATES,
873 };
874
875 static void
876 enroll_start_sm_cb_msg28 (FpDevice *dev,
877 enum read_msg_type type, guint8 seq,
878 unsigned char subcmd,
879 unsigned char *data, size_t data_len,
880 void *user_data,
881 GError *error)
882 {
883 FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev);
884 FpiSsm *ssm = user_data;
885
886 if (error)
887 {
888 fpi_ssm_mark_failed (ssm, error);
889 }
890 else if (type != READ_MSG_RESPONSE)
891 {
892 fp_err ("expected response, got %d seq=%x", type, seq);
893 fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
894 "Unexpected response type"));
895 }
896 else if (subcmd != 0)
897 {
898 fp_warn ("expected response to subcmd 0, got response to %02x",
899 subcmd);
900 fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
901 "Got response to wrong subcommand"));
902 }
903 else if (seq != upekdev->seq)
904 {
905 fp_err ("expected response to cmd seq=%02x, got response to %02x",
906 upekdev->seq, seq);
907 fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
908 "Got response with wrong sequence number"));
909 }
910 else
911 {
912 fpi_ssm_next_state (ssm);
913 }
914 }
915
916 static void
917 enroll_start_sm_run_state (FpiSsm *ssm, FpDevice *dev)
918 {
919 switch (fpi_ssm_get_cur_state (ssm))
920 {
921 case RUN_INITSM:;
922 FpiSsm *initsm = initsm_new (dev);
923 fpi_ssm_start_subsm (ssm, initsm);
924 break;
925
926 case ENROLL_INIT:;
927 FpiUsbTransfer *transfer;
928 transfer = alloc_send_cmd28_transfer (dev, 0x02, enroll_init, sizeof (enroll_init));
929 transfer->short_is_error = TRUE;
930 transfer->ssm = ssm;
931
932 fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
933 break;
934
935 case READ_ENROLL_MSG28:;
936 /* FIXME: protocol misunderstanding here. device receives response
937 * to subcmd 0 after submitting subcmd 2? */
938 /* actually this is probably a poll response? does the above cmd
939 * include a 30 01 poll somewhere? */
940 read_msg_async (dev, enroll_start_sm_cb_msg28, ssm);
941 break;
942 }
943 }
944
945 typedef struct
946 {
947 FpPrint *print;
948 GError *error;
949 } EnrollStopData;
950
951 static void
952 enroll_stop_data_free (EnrollStopData *data)
953 {
954 g_clear_object (&data->print);
955 g_clear_error (&data->error);
956 g_free (data);
957 }
958
959 static void
960 enroll_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
961 {
962 EnrollStopData *data = fpi_ssm_get_data (ssm);
963
964 /* don't really care about errors */
965 if (error)
966 fp_warn ("Error deinitializing: %s", error->message);
967
968 fpi_device_enroll_complete (dev,
969 g_steal_pointer (&data->print),
970 g_steal_pointer (&data->error));
971 }
972
973 static void
974 do_enroll_stop (FpDevice *dev, FpPrint *print, GError *error)
975 {
976 EnrollStopData *data = g_new0 (EnrollStopData, 1);
977 FpiSsm *ssm = deinitsm_new (dev, data);
978
979 data->print = print;
980 data->error = error;
981
982 fpi_ssm_start (ssm, enroll_stop_deinit_cb);
983 fpi_ssm_set_data (ssm, data, (GDestroyNotify) enroll_stop_data_free);
984 }
985
986 static void enroll_iterate (FpDevice *dev);
987
988 static void
989 e_handle_resp00 (FpDevice *dev, unsigned char *data,
990 size_t data_len)
991 {
992 FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev);
993 unsigned char status;
994
995 if (data_len != 14)
996 {
997 fp_err ("received 3001 poll response of %" G_GSIZE_FORMAT " bytes?", data_len);
998 do_enroll_stop (dev, NULL,
999 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1000 "received 3001 response with wrong length"));
1001 return;
1002 }
1003
1004 status = data[5];
1005 fp_dbg ("poll result = %02x", status);
1006
1007 switch (status)
1008 {
1009 case 0x0c:
1010 case 0x0d:
1011 case 0x0e:
1012 case 0x26:
1013 case 0x27:
1014 case 0x2e:
1015 /* if we previously completed a non-last enrollment stage, we'll
1016 * get this code to indicate successful stage completion */
1017 if (upekdev->enroll_passed)
1018 {
1019 upekdev->enroll_passed = FALSE;
1020 upekdev->enroll_stage += 1;
1021
1022 fpi_device_enroll_progress (dev, upekdev->enroll_stage, NULL, NULL);
1023 }
1024 /* otherwise it just means "no news" so we poll again */
1025 break;
1026
1027 case 0x1c: /* FIXME what does this one mean? */
1028 case 0x0b: /* FIXME what does this one mean? */
1029 case 0x23: /* FIXME what does this one mean? */
1030 fpi_device_enroll_progress (dev,
1031 upekdev->enroll_stage,
1032 NULL,
1033 fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
1034 break;
1035
1036 case 0x0f: /* scan taking too long, remove finger and try again */
1037 fpi_device_enroll_progress (dev,
1038 upekdev->enroll_stage,
1039 NULL,
1040 fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER));
1041 break;
1042
1043 case 0x1e: /* swipe too short */
1044 fpi_device_enroll_progress (dev,
1045 upekdev->enroll_stage,
1046 NULL,
1047 fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT));
1048 break;
1049
1050 case 0x24: /* finger not centered */
1051 fpi_device_enroll_progress (dev,
1052 upekdev->enroll_stage,
1053 NULL,
1054 fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER));
1055 break;
1056
1057 case 0x20:
1058 /* finger scanned successfully */
1059 /* need to look at the next poll result to determine if enrollment is
1060 * complete or not */
1061 upekdev->enroll_passed = TRUE;
1062 break;
1063
1064 case 0x00: /* enrollment complete */
1065 /* we can now expect the enrollment data on the next poll, so we
1066 * have nothing to do here */
1067 break;
1068
1069 default:
1070 do_enroll_stop (dev,
1071 NULL,
1072 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1073 "Unrecognised scan status code"));
1074 /* Stop iteration. */
1075 return;
1076 }
1077 enroll_iterate (dev);
1078
1079 /* FIXME: need to extend protocol research to handle the case when
1080 * enrolment fails, e.g. you scan a different finger on each stage */
1081 /* FIXME: should do proper tracking of when we expect cmd0 results and
1082 * cmd2 results and enforce it */
1083 }
1084
1085 static void
1086 e_handle_resp02 (FpDevice *dev, unsigned char *data,
1087 size_t data_len)
1088 {
1089 FpPrint *print = NULL;
1090 GError *error = NULL;
1091
1092 if (data_len < sizeof (scan_comp))
1093 {
1094 fp_err ("fingerprint data too short (%" G_GSIZE_FORMAT "u bytes)", data_len);
1095 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data too short");
1096 }
1097 else if (memcmp (data, scan_comp, sizeof (scan_comp)) != 0)
1098 {
1099 fp_err ("unrecognised data prefix %x %x %x %x %x",
1100 data[0], data[1], data[2], data[3], data[4]);
1101 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data has wrong prefix");
1102 }
1103 else
1104 {
1105 GVariant *fp_data;
1106
1107 fpi_device_get_enroll_data (dev, &print);
1108
1109 fp_data = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
1110 data + sizeof (scan_comp),
1111 data_len - sizeof (scan_comp),
1112 1);
1113
1114 fpi_print_set_type (print, FPI_PRINT_RAW);
1115 g_object_set (print, "fpi-data", fp_data, NULL);
1116 g_object_ref (print);
1117 }
1118
1119 do_enroll_stop (dev, print, error);
1120 }
1121
1122 static void
1123 enroll_iterate_msg_cb (FpDevice *dev,
1124 enum read_msg_type msgtype, guint8 seq,
1125 unsigned char subcmd,
1126 unsigned char *data, size_t data_len,
1127 void *user_data,
1128 GError *error)
1129 {
1130 if (error)
1131 {
1132 do_enroll_stop (dev, NULL, error);
1133 return;
1134 }
1135 else if (msgtype != READ_MSG_RESPONSE)
1136 {
1137 fp_err ("expected response, got %d seq=%x", msgtype, seq);
1138 do_enroll_stop (dev, NULL,
1139 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1140 "Expected message response, not command"));
1141 return;
1142 }
1143 if (subcmd == 0)
1144 {
1145 e_handle_resp00 (dev, data, data_len);
1146 }
1147 else if (subcmd == 2)
1148 {
1149 e_handle_resp02 (dev, data, data_len);
1150 }
1151 else
1152 {
1153 fp_err ("unexpected subcmd %d", subcmd);
1154 do_enroll_stop (dev, NULL,
1155 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1156 "Unexpected subcommand"));
1157 }
1158 }
1159
1160 static void
1161 enroll_iterate_cmd_cb (FpiUsbTransfer *transfer, FpDevice *device,
1162 gpointer user_data, GError *error)
1163 {
1164 if (error)
1165 do_enroll_stop (device, NULL, error);
1166 else
1167 read_msg_async (device, enroll_iterate_msg_cb, NULL);
1168 }
1169
1170 static void
1171 enroll_iterate (FpDevice *dev)
1172 {
1173 FpiUsbTransfer *transfer;
1174
1175 if (fpi_device_action_is_cancelled (dev))
1176 {
1177 do_enroll_stop (dev, NULL, g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled"));
1178 return;
1179 }
1180
1181 transfer = alloc_send_cmd28_transfer (dev, 0x00,
1182 poll_data, sizeof (poll_data));
1183 transfer->short_is_error = TRUE;
1184
1185 fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, enroll_iterate_cmd_cb, NULL);
1186 }
1187
1188 static void
1189 enroll_started (FpiSsm *ssm, FpDevice *dev, GError *error)
1190 {
1191 if (error)
1192 do_enroll_stop (dev, NULL, error);
1193 else
1194 enroll_iterate (dev);
1195
1196 }
1197
1198 static void
1199 enroll (FpDevice *dev)
1200 {
1201 FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev);
1202
1203 /* do_init state machine first */
1204 FpiSsm *ssm = fpi_ssm_new (dev, enroll_start_sm_run_state,
1205 ENROLL_START_NUM_STATES);
1206
1207 upekdev->enroll_passed = FALSE;
1208 upekdev->enroll_stage = 0;
1209 fpi_ssm_start (ssm, enroll_started);
1210 }
1211
1212 typedef struct
1213 {
1214 GError *error;
1215 } VerifyStopData;
1216
1217 static void
1218 verify_stop_data_free (VerifyStopData *data)
1219 {
1220 g_clear_error (&data->error);
1221 g_free (data);
1222 }
1223
1224 static void
1225 verify_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
1226 {
1227 VerifyStopData *data = fpi_ssm_get_data (ssm);
1228
1229 if (error)
1230 fp_warn ("Error deinitializing: %s", error->message);
1231
1232 if (data->error)
1233 fpi_device_verify_complete (dev, g_steal_pointer (&data->error));
1234 else
1235 fpi_device_verify_complete (dev, g_steal_pointer (&error));
1236
1237 g_clear_error (&error);
1238 }
1239
1240 static void
1241 do_verify_stop (FpDevice *dev, FpiMatchResult res, GError *error)
1242 {
1243 VerifyStopData *data = g_new0 (VerifyStopData, 1);
1244 FpiSsm *ssm = deinitsm_new (dev, data);
1245
1246 /* Report the error immediately if possible, otherwise delay it. */
1247 if (!error || error->domain == FP_DEVICE_RETRY)
1248 fpi_device_verify_report (dev, res, NULL, error);
1249 else
1250 data->error = error;
1251
1252 fpi_ssm_start (ssm, verify_stop_deinit_cb);
1253 fpi_ssm_set_data (ssm, data, (GDestroyNotify) verify_stop_data_free);
1254 }
1255
1256 static const unsigned char verify_hdr[] = {
1257 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1258 0x00, 0xc0, 0xd4, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
1259 0x00
1260 };
1261
1262 enum {
1263 VERIFY_RUN_INITSM = 0,
1264 VERIFY_INIT,
1265 VERIFY_NUM_STATES,
1266 };
1267
1268 static void
1269 verify_start_sm_run_state (FpiSsm *ssm, FpDevice *dev)
1270 {
1271 FpPrint *print;
1272
1273 g_autoptr(GVariant) fp_data = NULL;
1274 FpiUsbTransfer *transfer;
1275 gsize data_len;
1276 const guint8 *data;
1277 guint8 *msg;
1278 gsize msg_len;
1279
1280 switch (fpi_ssm_get_cur_state (ssm))
1281 {
1282 case VERIFY_RUN_INITSM:;
1283 FpiSsm *initsm = initsm_new (dev);
1284 fpi_ssm_start_subsm (ssm, initsm);
1285 break;
1286
1287 case VERIFY_INIT:
1288 fpi_device_get_verify_data (dev, &print);
1289 g_object_get (print, "fpi-data", &fp_data, NULL);
1290
1291 data = g_variant_get_fixed_array (fp_data, &data_len, 1);
1292
1293 msg_len = sizeof (verify_hdr) + data_len;
1294 msg = g_malloc (msg_len);
1295
1296 memcpy (msg, verify_hdr, sizeof (verify_hdr));
1297 memcpy (msg + sizeof (verify_hdr), data, data_len);
1298
1299 transfer = alloc_send_cmd28_transfer (dev, 0x03, msg, msg_len);
1300
1301 g_free (msg);
1302
1303 transfer->short_is_error = TRUE;
1304 transfer->ssm = ssm;
1305 fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
1306
1307 break;
1308 }
1309 }
1310
1311 static void verify_iterate (FpDevice *dev);
1312
1313 static void
1314 v_handle_resp00 (FpDevice *dev, unsigned char *data,
1315 size_t data_len)
1316 {
1317 unsigned char status;
1318 GError *error = NULL;
1319
1320 if (data_len != 14)
1321 {
1322 fp_warn ("received 3001 poll response of %" G_GSIZE_FORMAT "u bytes?", data_len);
1323 error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
1324 goto out;
1325 }
1326
1327 status = data[5];
1328 fp_dbg ("poll result = %02x", status);
1329
1330 /* These codes indicate that we're waiting for a finger scan, so poll
1331 * again */
1332 switch (status)
1333 {
1334 case 0x0c: /* no news, poll again */
1335 break;
1336
1337 case 0x20:
1338 fp_dbg ("processing scan for verification");
1339 break;
1340
1341 case 0x00:
1342 fp_dbg ("good image");
1343 break;
1344
1345 case 0x0b: /* FIXME what does this one mean? */
1346 case 0x23: /* FIXME what does this one mean? */
1347 error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
1348 break;
1349
1350 case 0x0f: /* scan taking too long, remove finger and try again */
1351 error = fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER);
1352 break;
1353
1354 case 0x1c: /* swipe too fast */
1355 error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_FAST);
1356 break;
1357
1358 case 0x1d: /* too much horizontal movement */
1359 error = fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER);
1360 break;
1361
1362 case 0x1e: /* swipe too short */
1363 error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT);
1364 break;
1365
1366 case 0x24: /* finger not centered */
1367 error = fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER);
1368 break;
1369
1370 default:
1371 fp_err ("unrecognised verify status code %02x", status);
1372 error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
1373 }
1374
1375 out:
1376 if (error)
1377 do_verify_stop (dev, FPI_MATCH_ERROR, error);
1378 else
1379 verify_iterate (dev);
1380 }
1381
1382 static void
1383 v_handle_resp03 (FpDevice *dev, unsigned char *data,
1384 size_t data_len)
1385 {
1386 FpiMatchResult r;
1387 GError *error = NULL;
1388
1389 if (data_len < 2)
1390 {
1391 fp_warn ("verify result abnormally short!");
1392 r = FPI_MATCH_ERROR;
1393 error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
1394 }
1395 else if (data[0] != 0x12)
1396 {
1397 fp_warn ("unexpected verify header byte %02x", data[0]);
1398 r = FPI_MATCH_ERROR;
1399 error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
1400 }
1401 else if (data[1] == 0x00)
1402 {
1403 r = FPI_MATCH_FAIL;
1404 }
1405 else if (data[1] == 0x01)
1406 {
1407 r = FPI_MATCH_SUCCESS;
1408 }
1409 else
1410 {
1411 fp_warn ("unrecognised verify result %02x", data[1]);
1412 r = FPI_MATCH_ERROR;
1413 error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
1414 }
1415 do_verify_stop (dev, r, error);
1416 }
1417
1418 static void
1419 verify_rd2800_cb (FpDevice *dev, enum read_msg_type msgtype,
1420 guint8 seq, unsigned char subcmd,
1421 unsigned char *data, size_t data_len,
1422 void *user_data,
1423 GError *error)
1424 {
1425 FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev);
1426
1427 if (error)
1428 {
1429 do_verify_stop (dev, FPI_MATCH_ERROR, error);
1430 return;
1431 }
1432
1433 if (msgtype != READ_MSG_RESPONSE)
1434 {
1435 fp_warn ("expected response, got %d seq=%x", msgtype, seq);
1436 do_verify_stop (dev,
1437 FPI_MATCH_ERROR,
1438 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1439 "Expected message response"));
1440 return;
1441 }
1442
1443 if (seq != upekdev->seq)
1444 {
1445 fp_warn ("expected response to cmd seq=%02x, got response to %02x",
1446 upekdev->seq, seq);
1447 do_verify_stop (dev,
1448 FPI_MATCH_ERROR,
1449 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1450 "Response had wrong command sequence"));
1451 return;
1452 }
1453
1454 if (subcmd == 0)
1455 {
1456 v_handle_resp00 (dev, data, data_len);
1457 }
1458 else if (subcmd == 3)
1459 {
1460 v_handle_resp03 (dev, data, data_len);
1461 }
1462 else
1463 {
1464 do_verify_stop (dev,
1465 FPI_MATCH_ERROR,
1466 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
1467 "Response had wrong subcommand type"));
1468 }
1469 }
1470
1471 static void
1472 verify_wr2800_cb (FpiUsbTransfer *transfer, FpDevice *device,
1473 gpointer user_data, GError *error)
1474 {
1475 if (error)
1476 {
1477 do_verify_stop (device,
1478 FPI_MATCH_ERROR,
1479 error);
1480 }
1481 else
1482 {
1483 read_msg_async (device, verify_rd2800_cb, NULL);
1484 }
1485 }
1486
1487 static void
1488 verify_iterate (FpDevice *dev)
1489 {
1490 FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev);
1491
1492 if (fpi_device_action_is_cancelled (dev))
1493 {
1494 do_verify_stop (dev, FPI_MATCH_ERROR, g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled"));
1495 return;
1496 }
1497
1498 /* FIXME: this doesn't flow well, should the first cmd be moved from
1499 * verify init to here? */
1500 if (upekdev->first_verify_iteration)
1501 {
1502 read_msg_async (dev, verify_rd2800_cb, NULL);
1503 upekdev->first_verify_iteration = FALSE;
1504 }
1505 else
1506 {
1507 FpiUsbTransfer *transfer = alloc_send_cmd28_transfer (dev,
1508 0x00, poll_data, sizeof (poll_data));
1509 transfer->short_is_error = TRUE;
1510
1511 fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, verify_wr2800_cb, NULL);
1512 }
1513 }
1514
1515 static void
1516 verify_started (FpiSsm *ssm, FpDevice *dev, GError *error)
1517 {
1518 FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev);
1519
1520 if (error)
1521 {
1522 do_verify_stop (dev, FPI_MATCH_ERROR, error);
1523 return;
1524 }
1525
1526 upekdev->first_verify_iteration = TRUE;
1527 verify_iterate (dev);
1528
1529 }
1530
1531 static void
1532 verify (FpDevice *dev)
1533 {
1534 FpiSsm *ssm = fpi_ssm_new (dev, verify_start_sm_run_state, VERIFY_NUM_STATES);
1535
1536 fpi_ssm_start (ssm, verify_started);
1537 }
1538
1539 static const FpIdEntry id_table[] = {
1540 { .vid = 0x0483, .pid = 0x2016, },
1541 { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
1542 };
1543
1544 static void
1545 fpi_device_upekts_init (FpiDeviceUpekts *self)
1546 {
1547 }
1548
1549 static void
1550 121 fpi_device_upekts_class_init (FpiDeviceUpektsClass *klass)
1551 {
1552 121 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
1553
1554 121 dev_class->id = FP_COMPONENT;
1555 121 dev_class->full_name = "UPEK TouchStrip";
1556
1557 121 dev_class->type = FP_DEVICE_TYPE_USB;
1558 121 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
1559 121 dev_class->id_table = id_table;
1560 121 dev_class->nr_enroll_stages = 3;
1561
1562 121 dev_class->open = dev_init;
1563 121 dev_class->close = dev_exit;
1564 121 dev_class->verify = verify;
1565 121 dev_class->enroll = enroll;
1566 /* dev_class->cancel = cancel; */
1567
1568 121 fpi_device_class_auto_initialize_features (dev_class);
1569 121 }
1570