GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 2.9% 17 / 0 / 590
Functions: 7.5% 4 / 0 / 53
Branches: 2.5% 4 / 0 / 163

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