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 128 times.
fpi_device_upekts_get_type:
✓ Branch 2 → 3 taken 128 times.
✓ Branch 2 → 7 taken 24 times.
✓ Branch 4 → 5 taken 128 times.
✗ Branch 4 → 7 not taken.
408 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 128 fpi_device_upekts_class_init (FpiDeviceUpektsClass *klass)
1559 {
1560 128 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
1561
1562 128 dev_class->id = FP_COMPONENT;
1563 128 dev_class->full_name = "UPEK TouchStrip";
1564
1565 128 dev_class->type = FP_DEVICE_TYPE_USB;
1566 128 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
1567 128 dev_class->id_table = id_table;
1568 128 dev_class->nr_enroll_stages = 3;
1569
1570 128 dev_class->open = dev_init;
1571 128 dev_class->close = dev_exit;
1572 128 dev_class->verify = verify;
1573 128 dev_class->enroll = enroll;
1574 /* dev_class->cancel = cancel; */
1575
1576 128 fpi_device_class_auto_initialize_features (dev_class);
1577 128 }
1578