GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/upekts.c
Date: 2024-05-04 14:54:39
Exec Total Coverage
Lines: 15 647 2.3%
Functions: 4 53 7.5%
Branches: 4 182 2.2%

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