Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Goodix Moc driver for libfprint | ||
3 | * Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd. | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2.1 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | |||
20 | |||
21 | |||
22 | #define FP_COMPONENT "goodixmoc" | ||
23 | |||
24 | #include "drivers_api.h" | ||
25 | |||
26 | #include "goodix_proto.h" | ||
27 | #include "goodix.h" | ||
28 | |||
29 | |||
30 | /* Default enroll stages number */ | ||
31 | #define DEFAULT_ENROLL_SAMPLES 8 | ||
32 | /* Usb port setting */ | ||
33 | #define EP_IN (3 | FPI_USB_ENDPOINT_IN) | ||
34 | #define EP_OUT (1 | FPI_USB_ENDPOINT_OUT) | ||
35 | |||
36 | #define EP_IN_MAX_BUF_SIZE (2048) | ||
37 | |||
38 | #define MAX_USER_ID_LEN (64) | ||
39 | |||
40 | /* Command transfer timeout :ms*/ | ||
41 | #define CMD_TIMEOUT (1000) | ||
42 | #define ACK_TIMEOUT (2000) | ||
43 | #define DATA_TIMEOUT (5000) | ||
44 | |||
45 | |||
46 | struct _FpiDeviceGoodixMoc | ||
47 | { | ||
48 | FpDevice parent; | ||
49 | FpiSsm *task_ssm; | ||
50 | FpiSsm *cmd_ssm; | ||
51 | FpiUsbTransfer *cmd_transfer; | ||
52 | gboolean cmd_cancelable; | ||
53 | pgxfp_sensor_cfg_t sensorcfg; | ||
54 | gint enroll_stage; | ||
55 | gint max_enroll_stage; | ||
56 | gint max_stored_prints; | ||
57 | GPtrArray *list_result; | ||
58 | guint8 template_id[TEMPLATE_ID_SIZE]; | ||
59 | gboolean is_power_button_shield_on; | ||
60 | |||
61 | }; | ||
62 | |||
63 |
4/5✓ Branch 0 taken 120 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 120 times.
✗ Branch 4 not taken.
|
768 | G_DEFINE_TYPE (FpiDeviceGoodixMoc, fpi_device_goodixmoc, FP_TYPE_DEVICE) |
64 | |||
65 | typedef void (*SynCmdMsgCallback) (FpiDeviceGoodixMoc *self, | ||
66 | gxfp_cmd_response_t *resp, | ||
67 | GError *error); | ||
68 | |||
69 | typedef struct | ||
70 | { | ||
71 | guint8 cmd; | ||
72 | SynCmdMsgCallback callback; | ||
73 | } CommandData; | ||
74 | |||
75 | static gboolean parse_print_data (GVariant *data, | ||
76 | guint8 *finger, | ||
77 | const guint8 **tid, | ||
78 | gsize *tid_len, | ||
79 | const guint8 **user_id, | ||
80 | gsize *user_id_len); | ||
81 | |||
82 | static FpPrint * | ||
83 | 3 | fp_print_from_template (FpiDeviceGoodixMoc *self, template_format_t *template) | |
84 | { | ||
85 | 3 | FpPrint *print; | |
86 | 3 | GVariant *data; | |
87 | 3 | GVariant *tid; | |
88 | 3 | GVariant *uid; | |
89 | 6 | g_autofree gchar *userid = NULL; | |
90 | |||
91 | 3 | userid = g_strndup ((gchar *) template->payload.data, template->payload.size); | |
92 | |||
93 | 3 | print = fp_print_new (FP_DEVICE (self)); | |
94 | |||
95 | 6 | tid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, | |
96 | 3 | template->tid, | |
97 | TEMPLATE_ID_SIZE, | ||
98 | 1); | ||
99 | |||
100 | 6 | uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, | |
101 | template->payload.data, | ||
102 | 3 | template->payload.size, | |
103 | 1); | ||
104 | |||
105 | 6 | data = g_variant_new ("(y@ay@ay)", | |
106 | 3 | template->finger_index, | |
107 | tid, | ||
108 | uid); | ||
109 | |||
110 | 3 | fpi_print_set_type (print, FPI_PRINT_RAW); | |
111 | 3 | fpi_print_set_device_stored (print, TRUE); | |
112 | 3 | g_object_set (print, "fpi-data", data, NULL); | |
113 | 3 | g_object_set (print, "description", userid, NULL); | |
114 | 3 | fpi_print_fill_from_user_id (print, userid); | |
115 | |||
116 | 3 | return print; | |
117 | } | ||
118 | |||
119 | /****************************************************************************** | ||
120 | * | ||
121 | * fp_cmd_xxx Function | ||
122 | * | ||
123 | *****************************************************************************/ | ||
124 | static void | ||
125 | 220 | fp_cmd_receive_cb (FpiUsbTransfer *transfer, | |
126 | FpDevice *device, | ||
127 | gpointer user_data, | ||
128 | GError *error) | ||
129 | { | ||
130 | 220 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
131 | 220 | CommandData *data = user_data; | |
132 | 220 | int ret = -1, ssm_state = 0; | |
133 | 220 | gxfp_cmd_response_t cmd_reponse = {0, }; | |
134 | 220 | pack_header header; | |
135 | 220 | guint32 crc32_calc = 0; | |
136 | 220 | guint16 cmd = 0; | |
137 | |||
138 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
|
220 | if (error) |
139 | { | ||
140 | ✗ | fpi_ssm_mark_failed (transfer->ssm, error); | |
141 | 165 | return; | |
142 | } | ||
143 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
|
220 | if (data == NULL) |
144 | { | ||
145 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
146 | fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); | ||
147 | ✗ | return; | |
148 | } | ||
149 | 220 | ssm_state = fpi_ssm_get_cur_state (transfer->ssm); | |
150 | /* skip zero length package */ | ||
151 |
2/2✓ Branch 0 taken 110 times.
✓ Branch 1 taken 110 times.
|
220 | if (transfer->actual_length == 0) |
152 | { | ||
153 | 110 | fpi_ssm_jump_to_state (transfer->ssm, ssm_state); | |
154 | 110 | return; | |
155 | } | ||
156 | |||
157 | 110 | ret = gx_proto_parse_header (transfer->buffer, transfer->actual_length, &header); | |
158 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
|
110 | if (ret != 0) |
159 | { | ||
160 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
161 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
162 | "Corrupted message header received")); | ||
163 | ✗ | return; | |
164 | } | ||
165 | |||
166 | 110 | gx_proto_crc32_calc (transfer->buffer, PACKAGE_HEADER_SIZE + header.len, (uint8_t *) &crc32_calc); | |
167 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
|
110 | if(crc32_calc != GUINT32_FROM_LE (*(uint32_t *) (transfer->buffer + PACKAGE_HEADER_SIZE + header.len))) |
168 | { | ||
169 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
170 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
171 | "Package crc check failed")); | ||
172 | ✗ | return; | |
173 | } | ||
174 | |||
175 | 110 | cmd = MAKE_CMD_EX (header.cmd0, header.cmd1); | |
176 | |||
177 | 110 | ret = gx_proto_parse_body (cmd, &transfer->buffer[PACKAGE_HEADER_SIZE], header.len, &cmd_reponse); | |
178 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
|
110 | if (ret != 0) |
179 | { | ||
180 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
181 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
182 | "Corrupted message received")); | ||
183 | ✗ | return; | |
184 | } | ||
185 | /* ack */ | ||
186 |
2/2✓ Branch 0 taken 55 times.
✓ Branch 1 taken 55 times.
|
110 | if(header.cmd0 == RESPONSE_PACKAGE_CMD) |
187 | { | ||
188 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | if (data->cmd != cmd_reponse.parse_msg.ack_cmd) |
189 | { | ||
190 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
191 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
192 | "Unexpected response, got 0x%x", | ||
193 | cmd_reponse.parse_msg.ack_cmd)); | ||
194 | |||
195 | ✗ | return; | |
196 | } | ||
197 | 55 | fpi_ssm_next_state (transfer->ssm); | |
198 | 55 | return; | |
199 | } | ||
200 | /* data */ | ||
201 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | if (data->cmd != header.cmd0) |
202 | { | ||
203 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
204 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
205 | "Unexpected cmd, got 0x%x", | ||
206 | header.cmd0)); | ||
207 | ✗ | return; | |
208 | } | ||
209 |
1/2✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
|
55 | if (data->callback) |
210 | 55 | data->callback (self, &cmd_reponse, NULL); | |
211 | |||
212 | 55 | fpi_ssm_mark_completed (transfer->ssm); | |
213 | } | ||
214 | |||
215 | |||
216 | static void | ||
217 | 275 | fp_cmd_run_state (FpiSsm *ssm, | |
218 | FpDevice *dev) | ||
219 | { | ||
220 | 275 | FpiUsbTransfer *transfer; | |
221 | 275 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (dev); | |
222 | |||
223 |
3/4✓ Branch 1 taken 55 times.
✓ Branch 2 taken 110 times.
✓ Branch 3 taken 110 times.
✗ Branch 4 not taken.
|
275 | switch (fpi_ssm_get_cur_state (ssm)) |
224 | { | ||
225 | 55 | case FP_CMD_SEND: | |
226 |
1/2✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
|
55 | if (self->cmd_transfer) |
227 | { | ||
228 | 55 | self->cmd_transfer->ssm = ssm; | |
229 | 55 | fpi_usb_transfer_submit (g_steal_pointer (&self->cmd_transfer), | |
230 | CMD_TIMEOUT, | ||
231 | NULL, | ||
232 | fpi_ssm_usb_transfer_cb, | ||
233 | NULL); | ||
234 | } | ||
235 | else | ||
236 | { | ||
237 | ✗ | fpi_ssm_next_state (ssm); | |
238 | } | ||
239 | break; | ||
240 | |||
241 | 110 | case FP_CMD_GET_ACK: | |
242 | 110 | transfer = fpi_usb_transfer_new (dev); | |
243 | 110 | transfer->ssm = ssm; | |
244 | 110 | fpi_usb_transfer_fill_bulk (transfer, EP_IN, EP_IN_MAX_BUF_SIZE); | |
245 | 110 | fpi_usb_transfer_submit (transfer, | |
246 | ACK_TIMEOUT, | ||
247 | NULL, | ||
248 | fp_cmd_receive_cb, | ||
249 | fpi_ssm_get_data (ssm)); | ||
250 | |||
251 | 110 | break; | |
252 | |||
253 | 110 | case FP_CMD_GET_DATA: | |
254 | 110 | transfer = fpi_usb_transfer_new (dev); | |
255 | 110 | transfer->ssm = ssm; | |
256 | 110 | fpi_usb_transfer_fill_bulk (transfer, EP_IN, EP_IN_MAX_BUF_SIZE); | |
257 | 110 | fpi_usb_transfer_submit (transfer, | |
258 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 50 times.
|
110 | self->cmd_cancelable ? 0 : DATA_TIMEOUT, |
259 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 60 times.
|
110 | self->cmd_cancelable ? fpi_device_get_cancellable (dev) : NULL, |
260 | fp_cmd_receive_cb, | ||
261 | fpi_ssm_get_data (ssm)); | ||
262 | 110 | break; | |
263 | } | ||
264 | |||
265 | 275 | } | |
266 | |||
267 | |||
268 | static void | ||
269 | 55 | fp_cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) | |
270 | { | ||
271 | 55 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (dev); | |
272 | 55 | CommandData *data = fpi_ssm_get_data (ssm); | |
273 | |||
274 | 55 | self->cmd_ssm = NULL; | |
275 | /* Notify about the SSM failure from here instead. */ | ||
276 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | if (error) |
277 | { | ||
278 | ✗ | if (data->callback) | |
279 | ✗ | data->callback (self, NULL, error); | |
280 | else | ||
281 | ✗ | g_error_free (error); | |
282 | } | ||
283 | 55 | } | |
284 | |||
285 | static FpiUsbTransfer * | ||
286 | 55 | alloc_cmd_transfer (FpDevice *dev, | |
287 | guint8 cmd0, | ||
288 | guint8 cmd1, | ||
289 | const guint8 *data, | ||
290 | guint16 data_len) | ||
291 | { | ||
292 | 55 | gint ret = -1; | |
293 | |||
294 | 110 | g_autoptr(FpiUsbTransfer) transfer = NULL; | |
295 | |||
296 | 55 | guint32 total_len = data_len + PACKAGE_HEADER_SIZE + PACKAGE_CRC_SIZE; | |
297 | |||
298 |
1/2✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
|
55 | g_return_val_if_fail (data || data_len == 0, NULL); |
299 | |||
300 | 55 | transfer = fpi_usb_transfer_new (dev); | |
301 | |||
302 | 55 | fpi_usb_transfer_fill_bulk (transfer, EP_OUT, total_len); | |
303 | |||
304 | 55 | ret = gx_proto_build_package (transfer->buffer, &total_len, MAKE_CMD_EX (cmd0, cmd1), data, data_len); | |
305 | |||
306 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | g_return_val_if_fail (ret == 0, NULL); |
307 | |||
308 | return g_steal_pointer (&transfer); | ||
309 | } | ||
310 | |||
311 | static void | ||
312 | 55 | fp_cmd_ssm_done_data_free (CommandData *data) | |
313 | { | ||
314 | 55 | g_free (data); | |
315 | 55 | } | |
316 | |||
317 | static void | ||
318 | 55 | goodix_sensor_cmd (FpiDeviceGoodixMoc *self, | |
319 | guint8 cmd0, | ||
320 | guint8 cmd1, | ||
321 | gboolean bwait_data_delay, | ||
322 | const guint8 * payload, | ||
323 | gssize payload_len, | ||
324 | SynCmdMsgCallback callback) | ||
325 | { | ||
326 | |||
327 | 110 | g_autoptr(FpiUsbTransfer) transfer = NULL; | |
328 | |||
329 | 55 | CommandData *data = g_new0 (CommandData, 1); | |
330 | |||
331 | 55 | transfer = alloc_cmd_transfer (FP_DEVICE (self), cmd0, cmd1, payload, payload_len); | |
332 | |||
333 | 55 | data->cmd = cmd0; | |
334 | 55 | data->callback = callback; | |
335 | |||
336 | 55 | self->cmd_transfer = g_steal_pointer (&transfer); | |
337 | 55 | self->cmd_cancelable = bwait_data_delay; | |
338 | |||
339 | 55 | self->cmd_ssm = fpi_ssm_new (FP_DEVICE (self), | |
340 | fp_cmd_run_state, | ||
341 | FP_CMD_NUM_STATES); | ||
342 | |||
343 | 55 | fpi_ssm_set_data (self->cmd_ssm, data, (GDestroyNotify) fp_cmd_ssm_done_data_free); | |
344 | |||
345 | 55 | fpi_ssm_start (self->cmd_ssm, fp_cmd_ssm_done); | |
346 | |||
347 | |||
348 | 55 | } | |
349 | |||
350 | /****************************************************************************** | ||
351 | * | ||
352 | * fp_pwr_btn_shield_cb Function | ||
353 | * | ||
354 | *****************************************************************************/ | ||
355 | static void | ||
356 | 6 | fp_pwr_btn_shield_cb (FpiDeviceGoodixMoc *self, | |
357 | gxfp_cmd_response_t *resp, | ||
358 | GError *error) | ||
359 | { | ||
360 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (error) |
361 | { | ||
362 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
363 | ✗ | return; | |
364 | } | ||
365 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (resp->result >= GX_FAILED) |
366 | { | ||
367 | ✗ | fp_dbg ("Setting power button shield failed, result: 0x%x", resp->result); | |
368 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
369 | fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); | ||
370 | ✗ | return; | |
371 | } | ||
372 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (resp->power_button_shield_resp.resp_cmd1 == MOC_CMD1_PWR_BTN_SHIELD_ON) |
373 | 3 | self->is_power_button_shield_on = true; | |
374 | else | ||
375 | 3 | self->is_power_button_shield_on = false; | |
376 | 6 | fpi_ssm_next_state (self->task_ssm); | |
377 | } | ||
378 | /****************************************************************************** | ||
379 | * | ||
380 | * fp_verify_xxxx Function | ||
381 | * | ||
382 | *****************************************************************************/ | ||
383 | static void | ||
384 | 2 | fp_verify_capture_cb (FpiDeviceGoodixMoc *self, | |
385 | gxfp_cmd_response_t *resp, | ||
386 | GError *error) | ||
387 | { | ||
388 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (error) |
389 | { | ||
390 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
391 | ✗ | return; | |
392 | } | ||
393 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (resp->result >= GX_FAILED) |
394 | { | ||
395 | ✗ | fp_dbg ("Capture sample failed, result: 0x%x", resp->result); | |
396 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
397 | fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); | ||
398 | ✗ | return; | |
399 | } | ||
400 | 2 | fpi_device_report_finger_status_changes (FP_DEVICE (self), | |
401 | FP_FINGER_STATUS_PRESENT, | ||
402 | FP_FINGER_STATUS_NONE); | ||
403 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (resp->capture_data_resp.img_quality == 0) |
404 | { | ||
405 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
406 | fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER)); | ||
407 | ✗ | return; | |
408 | } | ||
409 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | else if (resp->capture_data_resp.img_coverage < 35) |
410 | { | ||
411 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
412 | fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER)); | ||
413 | ✗ | return; | |
414 | } | ||
415 | 2 | fpi_ssm_next_state (self->task_ssm); | |
416 | } | ||
417 | |||
418 | static void | ||
419 | 2 | fp_verify_cb (FpiDeviceGoodixMoc *self, | |
420 | gxfp_cmd_response_t *resp, | ||
421 | GError *error) | ||
422 | { | ||
423 | 2 | FpDevice *device = FP_DEVICE (self); | |
424 | 2 | FpPrint *new_scan = NULL; | |
425 | 2 | FpPrint *matching = NULL; | |
426 | |||
427 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (error) |
428 | { | ||
429 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
430 | ✗ | return; | |
431 | } | ||
432 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (resp->verify.match) |
433 | { | ||
434 | 2 | new_scan = fp_print_from_template (self, &resp->verify.template); | |
435 | |||
436 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
|
2 | if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY) |
437 | { | ||
438 | 1 | fpi_device_get_verify_data (device, &matching); | |
439 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!fp_print_equal (matching, new_scan)) |
440 | ✗ | matching = NULL; | |
441 | } | ||
442 | else | ||
443 | { | ||
444 | 1 | GPtrArray *templates = NULL; | |
445 | 1 | fpi_device_get_identify_data (device, &templates); | |
446 | |||
447 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | for (gint i = 0; i < templates->len; i++) |
448 | { | ||
449 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if (fp_print_equal (g_ptr_array_index (templates, i), new_scan)) |
450 | { | ||
451 | 1 | matching = g_ptr_array_index (templates, i); | |
452 | 1 | break; | |
453 | } | ||
454 | } | ||
455 | } | ||
456 | } | ||
457 | |||
458 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
|
2 | if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY) |
459 | 1 | fpi_device_verify_report (device, matching ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL, new_scan, error); | |
460 | else | ||
461 | 1 | fpi_device_identify_report (device, matching, new_scan, error); | |
462 | |||
463 | 2 | fpi_ssm_next_state (self->task_ssm); | |
464 | |||
465 | } | ||
466 | |||
467 | static void | ||
468 | 8 | fp_verify_sm_run_state (FpiSsm *ssm, FpDevice *device) | |
469 | { | ||
470 | 8 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
471 | 8 | guint8 param[3] = { 0 }; | |
472 | 8 | guint8 nonce[TEMPLATE_ID_SIZE] = { 0 }; | |
473 | |||
474 | 8 | param[0] = 0x01; | |
475 | 8 | param[1] = self->sensorcfg->config[10]; | |
476 | 8 | param[2] = self->sensorcfg->config[11]; | |
477 | |||
478 |
4/5✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
8 | switch (fpi_ssm_get_cur_state (ssm)) |
479 | { | ||
480 | 2 | case FP_VERIFY_PWR_BTN_SHIELD_ON: | |
481 | 2 | goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_ON, | |
482 | false, | ||
483 | NULL, | ||
484 | 0, | ||
485 | fp_pwr_btn_shield_cb); | ||
486 | 2 | break; | |
487 | |||
488 | 2 | case FP_VERIFY_CAPTURE: | |
489 | 2 | fpi_device_report_finger_status_changes (device, | |
490 | FP_FINGER_STATUS_NEEDED, | ||
491 | FP_FINGER_STATUS_NONE); | ||
492 | 2 | goodix_sensor_cmd (self, MOC_CMD0_CAPTURE_DATA, MOC_CMD1_DEFAULT, | |
493 | true, | ||
494 | (const guint8 *) ¶m, | ||
495 | G_N_ELEMENTS (param), | ||
496 | fp_verify_capture_cb); | ||
497 | 2 | break; | |
498 | |||
499 | 2 | case FP_VERIFY_IDENTIFY: | |
500 | 2 | goodix_sensor_cmd (self, MOC_CMD0_IDENTIFY, MOC_CMD1_DEFAULT, | |
501 | false, | ||
502 | (const guint8 *) nonce, | ||
503 | TEMPLATE_ID_SIZE, | ||
504 | fp_verify_cb); | ||
505 | 2 | break; | |
506 | |||
507 | 2 | case FP_VERIFY_PWR_BTN_SHIELD_OFF: | |
508 | 2 | goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_OFF, | |
509 | false, | ||
510 | NULL, | ||
511 | 0, | ||
512 | fp_pwr_btn_shield_cb); | ||
513 | 2 | break; | |
514 | } | ||
515 | |||
516 | 8 | } | |
517 | |||
518 | static void | ||
519 | 2 | fp_verify_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) | |
520 | { | ||
521 | 2 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (dev); | |
522 | |||
523 | 2 | fp_info ("Verify complete!"); | |
524 | |||
525 |
1/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
2 | if (error && error->domain == FP_DEVICE_RETRY) |
526 | { | ||
527 | ✗ | if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY) | |
528 | ✗ | fpi_device_verify_report (dev, FPI_MATCH_ERROR, NULL, g_steal_pointer (&error)); | |
529 | else | ||
530 | ✗ | fpi_device_identify_report (dev, NULL, NULL, g_steal_pointer (&error)); | |
531 | } | ||
532 | |||
533 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
|
2 | if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_VERIFY) |
534 | 1 | fpi_device_verify_complete (dev, error); | |
535 | |||
536 | else | ||
537 | 1 | fpi_device_identify_complete (dev, error); | |
538 | |||
539 | 2 | self->task_ssm = NULL; | |
540 | 2 | } | |
541 | |||
542 | |||
543 | /****************************************************************************** | ||
544 | * | ||
545 | * fp__xxxx Function | ||
546 | * | ||
547 | *****************************************************************************/ | ||
548 | static gboolean | ||
549 | 2 | encode_finger_id ( | |
550 | const guint8 * tid, | ||
551 | guint16 tid_len, | ||
552 | const guint8 * uid, | ||
553 | guint16 uid_len, | ||
554 | guint8 ** fid, | ||
555 | guint16 * fid_len | ||
556 | ) | ||
557 | { | ||
558 | 2 | guint8 * buffer = NULL; | |
559 | 2 | guint16 offset = 0; | |
560 | |||
561 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | g_return_val_if_fail (tid != NULL, FALSE); |
562 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | g_return_val_if_fail (uid != NULL, FALSE); |
563 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | g_return_val_if_fail (fid != NULL, FALSE); |
564 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | g_return_val_if_fail (fid_len != NULL, FALSE); |
565 | |||
566 | 2 | *fid_len = (guint16) (70 + uid_len); // must include fingerid length | |
567 | |||
568 | 2 | *fid = (guint8 *) g_malloc0 (*fid_len + 2); | |
569 | |||
570 | 2 | buffer = *fid; | |
571 | 2 | offset = 0; | |
572 | 2 | buffer[offset++] = LOBYTE (*fid_len); | |
573 | 2 | buffer[offset++] = HIBYTE (*fid_len); | |
574 | |||
575 | 2 | buffer[offset++] = 67; | |
576 | 2 | buffer[offset++] = 1; | |
577 | 2 | buffer[offset++] = 1; // finger index | |
578 | 2 | buffer[offset++] = 0; // | |
579 | |||
580 | 2 | offset += 32; | |
581 | |||
582 | 2 | memcpy (&buffer[offset], tid, MIN (tid_len, TEMPLATE_ID_SIZE)); | |
583 | 2 | offset += 32; // offset == 68 | |
584 | |||
585 | 2 | buffer[offset++] = uid_len; | |
586 | 2 | memcpy (&buffer[offset], uid, uid_len); | |
587 | 2 | offset += (guint8) uid_len; | |
588 | |||
589 | 2 | buffer[offset++] = 0; | |
590 | |||
591 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (offset != (*fid_len + 2)) |
592 | { | ||
593 | ✗ | memset (buffer, 0, *fid_len); | |
594 | ✗ | *fid_len = 0; | |
595 | |||
596 | ✗ | fp_err ("offset != fid_len, %d != %d", offset, *fid_len); | |
597 | ✗ | return FALSE; | |
598 | } | ||
599 | 2 | *fid_len += 2; | |
600 | |||
601 | 2 | return TRUE; | |
602 | } | ||
603 | /****************************************************************************** | ||
604 | * | ||
605 | * fp_enroll_xxxx Function | ||
606 | * | ||
607 | *****************************************************************************/ | ||
608 | |||
609 | static void | ||
610 | 1 | fp_enroll_enum_cb (FpiDeviceGoodixMoc *self, | |
611 | gxfp_cmd_response_t *resp, | ||
612 | GError *error) | ||
613 | { | ||
614 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
615 | { | ||
616 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
617 | ✗ | return; | |
618 | } | ||
619 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (resp->result != GX_SUCCESS) |
620 | { | ||
621 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
622 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
623 | "Failed to enumerate fingers, result: 0x%x", | ||
624 | resp->result)); | ||
625 | ✗ | return; | |
626 | } | ||
627 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (resp->finger_list_resp.finger_num >= self->max_stored_prints) |
628 | { | ||
629 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
630 | fpi_device_error_new (FP_DEVICE_ERROR_DATA_FULL)); | ||
631 | ✗ | return; | |
632 | } | ||
633 | |||
634 | 1 | fpi_ssm_next_state (self->task_ssm); | |
635 | } | ||
636 | |||
637 | static void | ||
638 | 1 | fp_enroll_create_cb (FpiDeviceGoodixMoc *self, | |
639 | gxfp_cmd_response_t *resp, | ||
640 | GError *error) | ||
641 | { | ||
642 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
643 | { | ||
644 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
645 | ✗ | return; | |
646 | } | ||
647 | 1 | memcpy (self->template_id, resp->enroll_create.tid, TEMPLATE_ID_SIZE); | |
648 | 1 | fpi_ssm_next_state (self->task_ssm); | |
649 | } | ||
650 | |||
651 | static void | ||
652 | 12 | fp_enroll_capture_cb (FpiDeviceGoodixMoc *self, | |
653 | gxfp_cmd_response_t *resp, | ||
654 | GError *error) | ||
655 | { | ||
656 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (error) |
657 | { | ||
658 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
659 | ✗ | return; | |
660 | } | ||
661 | /* */ | ||
662 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (resp->result >= GX_FAILED) |
663 | { | ||
664 | ✗ | fp_info ("Capture sample failed, result: 0x%x", resp->result); | |
665 | ✗ | fpi_device_enroll_progress (FP_DEVICE (self), | |
666 | self->enroll_stage, | ||
667 | NULL, | ||
668 | fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); | ||
669 | ✗ | fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE); | |
670 | ✗ | return; | |
671 | } | ||
672 | 12 | fpi_device_report_finger_status_changes (FP_DEVICE (self), | |
673 | FP_FINGER_STATUS_PRESENT, | ||
674 | FP_FINGER_STATUS_NONE); | ||
675 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if ((resp->capture_data_resp.img_quality < self->sensorcfg->config[4]) || |
676 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | (resp->capture_data_resp.img_coverage < self->sensorcfg->config[5])) |
677 | { | ||
678 | ✗ | fp_info ("Capture sample poor quality(%d): %d or coverage(%d): %d", | |
679 | self->sensorcfg->config[4], | ||
680 | resp->capture_data_resp.img_quality, | ||
681 | self->sensorcfg->config[5], | ||
682 | resp->capture_data_resp.img_coverage); | ||
683 | ✗ | fpi_device_enroll_progress (FP_DEVICE (self), | |
684 | self->enroll_stage, | ||
685 | NULL, | ||
686 | fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER)); | ||
687 | ✗ | fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE); | |
688 | ✗ | return; | |
689 | } | ||
690 | else | ||
691 | { | ||
692 | 12 | fpi_ssm_next_state (self->task_ssm); | |
693 | } | ||
694 | |||
695 | } | ||
696 | static void | ||
697 | 12 | fp_enroll_update_cb (FpiDeviceGoodixMoc *self, | |
698 | gxfp_cmd_response_t *resp, | ||
699 | GError *error) | ||
700 | { | ||
701 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (error) |
702 | { | ||
703 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
704 | ✗ | return; | |
705 | } | ||
706 | |||
707 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (resp->enroll_update.img_preoverlay > self->sensorcfg->config[3]) |
708 | { | ||
709 | ✗ | fp_dbg ("Sample overlapping ratio is too High(%d): %d ", | |
710 | self->sensorcfg->config[3], | ||
711 | resp->enroll_update.img_preoverlay); | ||
712 | /* here should tips move finger and try again */ | ||
713 | ✗ | fpi_device_enroll_progress (FP_DEVICE (self), | |
714 | self->enroll_stage, | ||
715 | NULL, | ||
716 | fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER)); | ||
717 | } | ||
718 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | else if (resp->enroll_update.rollback) |
719 | { | ||
720 | ✗ | fpi_device_enroll_progress (FP_DEVICE (self), | |
721 | self->enroll_stage, | ||
722 | NULL, | ||
723 | fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); | ||
724 | } | ||
725 | else | ||
726 | { | ||
727 | 12 | self->enroll_stage++; | |
728 | 12 | fpi_device_enroll_progress (FP_DEVICE (self), self->enroll_stage, NULL, NULL); | |
729 | } | ||
730 | /* if enroll complete, no need to wait finger up */ | ||
731 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
|
12 | if (self->enroll_stage >= self->max_enroll_stage) |
732 | { | ||
733 | 1 | fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CHECK_DUPLICATE); | |
734 | 1 | return; | |
735 | } | ||
736 | |||
737 | 11 | fpi_ssm_next_state (self->task_ssm); | |
738 | } | ||
739 | |||
740 | static void | ||
741 | 1 | fp_enroll_check_duplicate_cb (FpiDeviceGoodixMoc *self, | |
742 | gxfp_cmd_response_t *resp, | ||
743 | GError *error) | ||
744 | { | ||
745 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
746 | { | ||
747 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
748 | ✗ | return; | |
749 | } | ||
750 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (resp->check_duplicate_resp.duplicate) |
751 | { | ||
752 | 1 | g_autoptr(FpPrint) print = NULL; | |
753 | |||
754 | ✗ | print = g_object_ref_sink (fp_print_from_template (self, &resp->check_duplicate_resp.template)); | |
755 | |||
756 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
757 | fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_DUPLICATE, | ||
758 | "Finger was already enrolled as '%s'", | ||
759 | fp_print_get_description (print))); | ||
760 | ✗ | return; | |
761 | } | ||
762 | |||
763 | 1 | fpi_ssm_next_state (self->task_ssm); | |
764 | } | ||
765 | |||
766 | static void | ||
767 | 1 | fp_enroll_commit_cb (FpiDeviceGoodixMoc *self, | |
768 | gxfp_cmd_response_t *resp, | ||
769 | GError *error) | ||
770 | { | ||
771 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
772 | { | ||
773 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
774 | ✗ | return; | |
775 | } | ||
776 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (resp->result >= GX_FAILED) |
777 | { | ||
778 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
779 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
780 | "Commit template failed with errcode: 0x%x", resp->result)); | ||
781 | ✗ | return; | |
782 | } | ||
783 | 1 | fpi_ssm_next_state (self->task_ssm); | |
784 | } | ||
785 | |||
786 | static void | ||
787 | 11 | fp_finger_mode_cb (FpiDeviceGoodixMoc *self, | |
788 | gxfp_cmd_response_t *resp, | ||
789 | GError *error) | ||
790 | { | ||
791 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | if (error) |
792 | { | ||
793 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
794 | ✗ | return; | |
795 | } | ||
796 | /* if reach max timeout(5sec) finger not up, switch to finger up again */ | ||
797 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | if (resp->finger_status.status == GX_ERROR_WAIT_FINGER_UP_TIMEOUT) |
798 | { | ||
799 | ✗ | fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_WAIT_FINGER_UP); | |
800 | ✗ | return; | |
801 | } | ||
802 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | else if (resp->finger_status.status != GX_SUCCESS) |
803 | { | ||
804 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
805 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
806 | "Switch finger mode failed")); | ||
807 | ✗ | return; | |
808 | } | ||
809 | 11 | fpi_device_report_finger_status_changes (FP_DEVICE (self), | |
810 | FP_FINGER_STATUS_NONE, | ||
811 | FP_FINGER_STATUS_PRESENT); | ||
812 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | if (self->enroll_stage < self->max_enroll_stage) |
813 | { | ||
814 | 11 | fpi_ssm_jump_to_state (self->task_ssm, FP_ENROLL_CAPTURE); | |
815 | 11 | return; | |
816 | } | ||
817 | ✗ | fpi_ssm_next_state (self->task_ssm); | |
818 | } | ||
819 | |||
820 | static void | ||
821 | 41 | fp_enroll_sm_run_state (FpiSsm *ssm, FpDevice *device) | |
822 | { | ||
823 | 41 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
824 | 41 | FpPrint *print = NULL; | |
825 | 41 | GVariant *data = NULL; | |
826 | 41 | GVariant *uid = NULL; | |
827 | 41 | GVariant *tid = NULL; | |
828 | 41 | guint finger; | |
829 | 41 | guint16 user_id_len; | |
830 | 41 | guint16 payload_len = 0; | |
831 | 41 | g_autofree gchar *user_id = NULL; | |
832 | 41 | g_autofree guint8 *payload = NULL; | |
833 | 41 | guint8 dummy[3] = { 0 }; | |
834 | |||
835 | 41 | dummy[1] = self->sensorcfg->config[4]; | |
836 | 41 | dummy[2] = self->sensorcfg->config[5]; | |
837 | |||
838 |
9/10✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 12 times.
✓ Branch 7 taken 11 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 1 times.
|
41 | switch (fpi_ssm_get_cur_state (ssm)) |
839 | { | ||
840 | 1 | case FP_ENROLL_PWR_BTN_SHIELD_ON: | |
841 | { | ||
842 | 1 | goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_ON, | |
843 | false, | ||
844 | NULL, | ||
845 | 0, | ||
846 | fp_pwr_btn_shield_cb); | ||
847 | } | ||
848 | 1 | break; | |
849 | |||
850 | 1 | case FP_ENROLL_ENUM: | |
851 | { | ||
852 | 1 | goodix_sensor_cmd (self, MOC_CMD0_GETFINGERLIST, MOC_CMD1_DEFAULT, | |
853 | false, | ||
854 | (const guint8 *) &dummy, | ||
855 | 1, | ||
856 | fp_enroll_enum_cb); | ||
857 | } | ||
858 | 1 | break; | |
859 | |||
860 | 1 | case FP_ENROLL_CREATE: | |
861 | { | ||
862 | 1 | goodix_sensor_cmd (self, MOC_CMD0_ENROLL_INIT, MOC_CMD1_DEFAULT, | |
863 | false, | ||
864 | (const guint8 *) &dummy, | ||
865 | 1, | ||
866 | fp_enroll_create_cb); | ||
867 | } | ||
868 | 1 | break; | |
869 | |||
870 | 12 | case FP_ENROLL_CAPTURE: | |
871 | 12 | fpi_device_report_finger_status_changes (device, | |
872 | FP_FINGER_STATUS_NEEDED, | ||
873 | FP_FINGER_STATUS_NONE); | ||
874 | 12 | goodix_sensor_cmd (self, MOC_CMD0_CAPTURE_DATA, MOC_CMD1_DEFAULT, | |
875 | true, | ||
876 | (const guint8 *) &dummy, | ||
877 | 3, | ||
878 | fp_enroll_capture_cb); | ||
879 | 12 | break; | |
880 | |||
881 | 12 | case FP_ENROLL_UPDATE: | |
882 | 12 | dummy[0] = 1; | |
883 | 12 | dummy[1] = self->sensorcfg->config[2]; | |
884 | 12 | dummy[2] = self->sensorcfg->config[3]; | |
885 | 12 | goodix_sensor_cmd (self, MOC_CMD0_ENROLL, MOC_CMD1_DEFAULT, | |
886 | false, | ||
887 | (const guint8 *) &dummy, | ||
888 | 3, | ||
889 | fp_enroll_update_cb); | ||
890 | 12 | break; | |
891 | |||
892 | 11 | case FP_ENROLL_WAIT_FINGER_UP: | |
893 | 11 | dummy[0] = 0; | |
894 | 11 | goodix_sensor_cmd (self, MOC_CMD0_FINGER_MODE, MOC_CMD1_SET_FINGER_UP, | |
895 | true, | ||
896 | (const guint8 *) &dummy, | ||
897 | 1, | ||
898 | fp_finger_mode_cb); | ||
899 | 11 | break; | |
900 | |||
901 | 1 | case FP_ENROLL_CHECK_DUPLICATE: | |
902 | 1 | goodix_sensor_cmd (self, MOC_CMD0_CHECK4DUPLICATE, MOC_CMD1_DEFAULT, | |
903 | false, | ||
904 | (const guint8 *) &dummy, | ||
905 | 3, | ||
906 | fp_enroll_check_duplicate_cb); | ||
907 | 1 | break; | |
908 | |||
909 | 1 | case FP_ENROLL_COMMIT: | |
910 | { | ||
911 | 1 | fpi_device_get_enroll_data (device, &print); | |
912 | 1 | user_id = fpi_print_generate_user_id (print); | |
913 | 1 | user_id_len = strlen (user_id); | |
914 | 1 | user_id_len = MIN (100, user_id_len); | |
915 | 1 | finger = 1; | |
916 | |||
917 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0) |
918 | 1 | memset (self->template_id, 0, TEMPLATE_ID_SIZE); | |
919 | 1 | uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, | |
920 | user_id, | ||
921 | user_id_len, | ||
922 | 1); | ||
923 | |||
924 | 2 | tid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, | |
925 | 1 | self->template_id, | |
926 | TEMPLATE_ID_SIZE, | ||
927 | 1); | ||
928 | |||
929 | 1 | data = g_variant_new ("(y@ay@ay)", | |
930 | finger, | ||
931 | tid, | ||
932 | uid); | ||
933 | |||
934 | 1 | fpi_print_set_type (print, FPI_PRINT_RAW); | |
935 | 1 | fpi_print_set_device_stored (print, TRUE); | |
936 | 1 | g_object_set (print, "fpi-data", data, NULL); | |
937 | 1 | g_object_set (print, "description", user_id, NULL); | |
938 | |||
939 | 1 | g_debug ("user_id: %s, user_id_len: %d, finger: %d", user_id, user_id_len, finger); | |
940 | |||
941 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if(!encode_finger_id (self->template_id, |
942 | TEMPLATE_ID_SIZE, | ||
943 | (guint8 *) user_id, | ||
944 | user_id_len, | ||
945 | &payload, | ||
946 | &payload_len)) | ||
947 | { | ||
948 | ✗ | fpi_ssm_mark_failed (ssm, | |
949 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
950 | "encode_finger_id failed")); | ||
951 | ✗ | return; | |
952 | } | ||
953 | 1 | goodix_sensor_cmd (self, MOC_CMD0_COMMITENROLLMENT, MOC_CMD1_DEFAULT, | |
954 | false, | ||
955 | (const guint8 *) payload, | ||
956 | payload_len, | ||
957 | fp_enroll_commit_cb); | ||
958 | |||
959 | } | ||
960 | 1 | break; | |
961 | |||
962 | 1 | case FP_ENROLL_PWR_BTN_SHIELD_OFF: | |
963 | { | ||
964 | 1 | goodix_sensor_cmd (self, MOC_CMD0_PWR_BTN_SHIELD, MOC_CMD1_PWR_BTN_SHIELD_OFF, | |
965 | false, | ||
966 | NULL, | ||
967 | 0, | ||
968 | fp_pwr_btn_shield_cb); | ||
969 | } | ||
970 | 1 | break; | |
971 | } | ||
972 | } | ||
973 | |||
974 | static void | ||
975 | 1 | fp_enroll_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) | |
976 | { | ||
977 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (dev); | |
978 | 1 | FpPrint *print = NULL; | |
979 | |||
980 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
981 | { | ||
982 | ✗ | fpi_device_enroll_complete (dev, NULL, error); | |
983 | ✗ | return; | |
984 | } | ||
985 | 1 | fp_info ("Enrollment complete!"); | |
986 | |||
987 | 1 | fpi_device_get_enroll_data (FP_DEVICE (self), &print); | |
988 | |||
989 | 1 | fpi_device_enroll_complete (FP_DEVICE (self), g_object_ref (print), NULL); | |
990 | |||
991 | 1 | self->task_ssm = NULL; | |
992 | } | ||
993 | /****************************************************************************** | ||
994 | * | ||
995 | * fp_init_xxxx Function | ||
996 | * | ||
997 | *****************************************************************************/ | ||
998 | static void | ||
999 | 1 | fp_init_version_cb (FpiDeviceGoodixMoc *self, | |
1000 | gxfp_cmd_response_t *resp, | ||
1001 | GError *error) | ||
1002 | { | ||
1003 | 1 | g_autofree gchar *fw_type = NULL; | |
1004 | 1 | g_autofree gchar *fw_version = NULL; | |
1005 | |||
1006 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1007 | { | ||
1008 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
1009 | ✗ | return; | |
1010 | } | ||
1011 | |||
1012 | 1 | G_STATIC_ASSERT (sizeof (resp->version_info.fwtype) == 8); | |
1013 | 1 | G_STATIC_ASSERT (sizeof (resp->version_info.fwversion) == 8); | |
1014 | |||
1015 | 1 | fw_type = g_strndup ((const char *) resp->version_info.fwtype, sizeof (resp->version_info.fwtype)); | |
1016 | |||
1017 | 1 | fp_info ("Firmware type: %s", fw_type); | |
1018 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (g_strcmp0 (fw_type, "APP") != 0) |
1019 | { | ||
1020 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
1021 | fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, | ||
1022 | "Please update firmware using fwupd")); | ||
1023 | ✗ | return; | |
1024 | } | ||
1025 | 1 | fw_version = g_strndup ((const char *) resp->version_info.fwversion, sizeof (resp->version_info.fwversion)); | |
1026 | 1 | fp_info ("Firmware version: %s", fw_version); | |
1027 | 1 | fpi_ssm_next_state (self->task_ssm); | |
1028 | } | ||
1029 | |||
1030 | static void | ||
1031 | 1 | fp_init_config_cb (FpiDeviceGoodixMoc *self, | |
1032 | gxfp_cmd_response_t *resp, | ||
1033 | GError *error) | ||
1034 | { | ||
1035 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1036 | { | ||
1037 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
1038 | ✗ | return; | |
1039 | } | ||
1040 | 1 | self->max_stored_prints = resp->finger_config.max_stored_prints; | |
1041 | 1 | fpi_ssm_next_state (self->task_ssm); | |
1042 | } | ||
1043 | |||
1044 | static void | ||
1045 | 1 | fp_init_cb_reset_or_complete (FpiDeviceGoodixMoc *self, | |
1046 | gxfp_cmd_response_t *resp, | ||
1047 | GError *error) | ||
1048 | { | ||
1049 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1050 | { | ||
1051 | ✗ | fp_warn ("Template storage appears to have been corrupted! Error was: %s", error->message); | |
1052 | ✗ | fp_warn ("A known reason for this to happen is a firmware bug triggered by another storage area being initialized."); | |
1053 | ✗ | fpi_ssm_jump_to_state (self->task_ssm, FP_INIT_RESET_DEVICE); | |
1054 | } | ||
1055 | else | ||
1056 | { | ||
1057 | 1 | fpi_ssm_mark_completed (self->task_ssm); | |
1058 | } | ||
1059 | 1 | } | |
1060 | |||
1061 | static void | ||
1062 | ✗ | fp_init_reset_device_cb (FpiDeviceGoodixMoc *self, | |
1063 | gxfp_cmd_response_t *resp, | ||
1064 | GError *error) | ||
1065 | { | ||
1066 | ✗ | if (error) | |
1067 | { | ||
1068 | ✗ | fp_warn ("Reset failed: %s", error->message); | |
1069 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
1070 | ✗ | return; | |
1071 | } | ||
1072 | ✗ | if ((resp->result >= GX_FAILED) && (resp->result != GX_ERROR_FINGER_ID_NOEXIST)) | |
1073 | { | ||
1074 | ✗ | fp_warn ("Reset failed, device reported: 0x%x", resp->result); | |
1075 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
1076 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
1077 | "Failed clear storage, result: 0x%x", | ||
1078 | ✗ | resp->result)); | |
1079 | ✗ | return; | |
1080 | } | ||
1081 | |||
1082 | ✗ | fp_warn ("Reset completed"); | |
1083 | ✗ | fpi_ssm_mark_completed (self->task_ssm); | |
1084 | } | ||
1085 | |||
1086 | static void | ||
1087 | 3 | fp_init_sm_run_state (FpiSsm *ssm, FpDevice *device) | |
1088 | { | ||
1089 | 3 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1090 | 3 | guint8 dummy = 0; | |
1091 | |||
1092 |
3/5✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
3 | switch (fpi_ssm_get_cur_state (ssm)) |
1093 | { | ||
1094 | 1 | case FP_INIT_VERSION: | |
1095 | 1 | goodix_sensor_cmd (self, MOC_CMD0_GET_VERSION, MOC_CMD1_DEFAULT, | |
1096 | false, | ||
1097 | &dummy, | ||
1098 | 1, | ||
1099 | fp_init_version_cb); | ||
1100 | 1 | break; | |
1101 | |||
1102 | 1 | case FP_INIT_CONFIG: | |
1103 | 1 | goodix_sensor_cmd (self, MOC_CMD0_UPDATE_CONFIG, MOC_CMD1_WRITE_CFG_TO_FLASH, | |
1104 | false, | ||
1105 | 1 | (guint8 *) self->sensorcfg, | |
1106 | sizeof (gxfp_sensor_cfg_t), | ||
1107 | fp_init_config_cb); | ||
1108 | 1 | break; | |
1109 | |||
1110 | 1 | case FP_INIT_TEMPLATE_LIST: | |
1111 | /* List prints to check whether the template DB was corrupted. | ||
1112 | * As of 2022-06-13 there is a known firmware issue that can cause the | ||
1113 | * stored templates for Linux to be corrupted when the Windows storage | ||
1114 | * area is initialized. | ||
1115 | * In that case, we'll get a protocol failure trying to retrieve the | ||
1116 | * list of prints. | ||
1117 | */ | ||
1118 | 1 | goodix_sensor_cmd (self, MOC_CMD0_GETFINGERLIST, MOC_CMD1_DEFAULT, | |
1119 | FALSE, | ||
1120 | (const guint8 *) &dummy, | ||
1121 | 1, | ||
1122 | fp_init_cb_reset_or_complete); | ||
1123 | 1 | break; | |
1124 | |||
1125 | ✗ | case FP_INIT_RESET_DEVICE: | |
1126 | ✗ | fp_warn ("Resetting device storage, you will need to enroll all prints again!"); | |
1127 | ✗ | goodix_sensor_cmd (self, MOC_CMD0_DELETETEMPLATE, MOC_CMD1_DELETE_ALL, | |
1128 | FALSE, | ||
1129 | NULL, | ||
1130 | 0, | ||
1131 | fp_init_reset_device_cb); | ||
1132 | ✗ | break; | |
1133 | } | ||
1134 | |||
1135 | |||
1136 | 3 | } | |
1137 | |||
1138 | static void | ||
1139 | 1 | fp_init_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) | |
1140 | { | ||
1141 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (dev); | |
1142 | |||
1143 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1144 | { | ||
1145 | ✗ | fpi_device_open_complete (dev, error); | |
1146 | ✗ | return; | |
1147 | } | ||
1148 | 1 | self->task_ssm = NULL; | |
1149 | 1 | fpi_device_open_complete (dev, NULL); | |
1150 | } | ||
1151 | /****************************************************************************** | ||
1152 | * | ||
1153 | * fp_template_delete Function | ||
1154 | * | ||
1155 | *****************************************************************************/ | ||
1156 | static gboolean | ||
1157 | 1 | parse_print_data (GVariant *data, | |
1158 | guint8 *finger, | ||
1159 | const guint8 **tid, | ||
1160 | gsize *tid_len, | ||
1161 | const guint8 **user_id, | ||
1162 | gsize *user_id_len) | ||
1163 | { | ||
1164 | 2 | g_autoptr(GVariant) user_id_var = NULL; | |
1165 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | g_autoptr(GVariant) tid_var = NULL; |
1166 | |||
1167 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | g_return_val_if_fail (data != NULL, FALSE); |
1168 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_return_val_if_fail (finger != NULL, FALSE); |
1169 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_return_val_if_fail (tid != NULL, FALSE); |
1170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_return_val_if_fail (tid_len != NULL, FALSE); |
1171 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_return_val_if_fail (user_id != NULL, FALSE); |
1172 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_return_val_if_fail (user_id_len != NULL, FALSE); |
1173 | |||
1174 | 1 | *tid = NULL; | |
1175 | 1 | *tid_len = 0; | |
1176 | 1 | *user_id = NULL; | |
1177 | 1 | *user_id_len = 0; | |
1178 | |||
1179 | |||
1180 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!g_variant_check_format_string (data, "(y@ay@ay)", FALSE)) |
1181 | return FALSE; | ||
1182 | |||
1183 | 1 | g_variant_get (data, | |
1184 | "(y@ay@ay)", | ||
1185 | finger, | ||
1186 | &tid_var, | ||
1187 | &user_id_var); | ||
1188 | |||
1189 | 1 | *tid = g_variant_get_fixed_array (tid_var, tid_len, 1); | |
1190 | 1 | *user_id = g_variant_get_fixed_array (user_id_var, user_id_len, 1); | |
1191 | |||
1192 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (*user_id_len == 0 || *user_id_len > 100) |
1193 | return FALSE; | ||
1194 | |||
1195 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (*user_id_len <= 0 || *user_id[0] == ' ') |
1196 | return FALSE; | ||
1197 | |||
1198 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if(*tid_len != TEMPLATE_ID_SIZE) |
1199 | return FALSE; | ||
1200 | |||
1201 | return TRUE; | ||
1202 | } | ||
1203 | |||
1204 | static void | ||
1205 | 1 | fp_template_delete_cb (FpiDeviceGoodixMoc *self, | |
1206 | gxfp_cmd_response_t *resp, | ||
1207 | GError *error) | ||
1208 | { | ||
1209 | 1 | FpDevice *device = FP_DEVICE (self); | |
1210 | |||
1211 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1212 | { | ||
1213 | ✗ | fpi_device_delete_complete (device, error); | |
1214 | ✗ | return; | |
1215 | } | ||
1216 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if ((resp->result >= GX_FAILED) && (resp->result != GX_ERROR_FINGER_ID_NOEXIST)) |
1217 | { | ||
1218 | ✗ | fpi_device_delete_complete (FP_DEVICE (self), | |
1219 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
1220 | "Failed delete enrolled users, result: 0x%x", | ||
1221 | resp->result)); | ||
1222 | ✗ | return; | |
1223 | } | ||
1224 | |||
1225 | 1 | fp_info ("Successfully deleted enrolled user"); | |
1226 | 1 | fpi_device_delete_complete (device, NULL); | |
1227 | } | ||
1228 | |||
1229 | static void | ||
1230 | 1 | fp_template_delete_all_cb (FpiDeviceGoodixMoc *self, | |
1231 | gxfp_cmd_response_t *resp, | ||
1232 | GError *error) | ||
1233 | { | ||
1234 | 1 | FpDevice *device = FP_DEVICE (self); | |
1235 | |||
1236 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1237 | { | ||
1238 | ✗ | fpi_device_clear_storage_complete (device, error); | |
1239 | ✗ | return; | |
1240 | } | ||
1241 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if ((resp->result >= GX_FAILED) && (resp->result != GX_ERROR_FINGER_ID_NOEXIST)) |
1242 | { | ||
1243 | ✗ | fpi_device_clear_storage_complete (FP_DEVICE (self), | |
1244 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
1245 | "Failed clear storage, result: 0x%x", | ||
1246 | resp->result)); | ||
1247 | ✗ | return; | |
1248 | } | ||
1249 | |||
1250 | 1 | fp_info ("Successfully cleared storage"); | |
1251 | 1 | fpi_device_clear_storage_complete (device, NULL); | |
1252 | } | ||
1253 | |||
1254 | /****************************************************************************** | ||
1255 | * | ||
1256 | * fp_template_list Function | ||
1257 | * | ||
1258 | *****************************************************************************/ | ||
1259 | static void | ||
1260 | 1 | fp_template_list_cb (FpiDeviceGoodixMoc *self, | |
1261 | gxfp_cmd_response_t *resp, | ||
1262 | GError *error) | ||
1263 | { | ||
1264 | 1 | FpDevice *device = FP_DEVICE (self); | |
1265 | |||
1266 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1267 | { | ||
1268 | ✗ | fpi_device_list_complete (FP_DEVICE (self), NULL, error); | |
1269 | ✗ | return; | |
1270 | } | ||
1271 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (resp->result != GX_SUCCESS) |
1272 | { | ||
1273 | ✗ | fp_info ("Failed to query enrolled users: %d", resp->result); | |
1274 | ✗ | fpi_device_list_complete (FP_DEVICE (self), | |
1275 | NULL, | ||
1276 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
1277 | "Failed to query enrolled users, result: 0x%x", | ||
1278 | ✗ | resp->result)); | |
1279 | ✗ | return; | |
1280 | } | ||
1281 | |||
1282 | 1 | self->list_result = g_ptr_array_new_with_free_func (g_object_unref); | |
1283 | |||
1284 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if(resp->finger_list_resp.finger_num == 0) |
1285 | { | ||
1286 | ✗ | fp_info ("Database is empty"); | |
1287 | ✗ | fpi_device_list_complete (device, | |
1288 | ✗ | g_steal_pointer (&self->list_result), | |
1289 | NULL); | ||
1290 | ✗ | return; | |
1291 | } | ||
1292 | |||
1293 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (int n = 0; n < resp->finger_list_resp.finger_num; n++) |
1294 | { | ||
1295 | 1 | FpPrint *print; | |
1296 | |||
1297 | 1 | print = fp_print_from_template (self, &resp->finger_list_resp.finger_list[n]); | |
1298 | |||
1299 | 1 | g_ptr_array_add (self->list_result, g_object_ref_sink (print)); | |
1300 | } | ||
1301 | |||
1302 | 1 | fp_info ("Query complete!"); | |
1303 | 1 | fpi_device_list_complete (device, | |
1304 | 1 | g_steal_pointer (&self->list_result), | |
1305 | NULL); | ||
1306 | |||
1307 | } | ||
1308 | |||
1309 | /****************************************************************************** | ||
1310 | * | ||
1311 | * Interface Function | ||
1312 | * | ||
1313 | *****************************************************************************/ | ||
1314 | static void | ||
1315 | 1 | gx_fp_probe (FpDevice *device) | |
1316 | { | ||
1317 | 1 | GUsbDevice *usb_dev; | |
1318 | 1 | GError *error = NULL; | |
1319 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1320 | 1 | g_autofree gchar *serial = NULL; | |
1321 | 1 | gint productid = 0; | |
1322 | |||
1323 | /* Claim usb interface */ | ||
1324 | 1 | usb_dev = fpi_device_get_usb_device (device); | |
1325 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!g_usb_device_open (usb_dev, &error)) |
1326 | { | ||
1327 | ✗ | fpi_device_probe_complete (device, NULL, NULL, error); | |
1328 | ✗ | return; | |
1329 | } | ||
1330 | |||
1331 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!g_usb_device_reset (usb_dev, &error)) |
1332 | ✗ | goto err_close; | |
1333 | |||
1334 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error)) |
1335 | ✗ | goto err_close; | |
1336 | |||
1337 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0) |
1338 | { | ||
1339 | |||
1340 | 1 | serial = g_strdup ("emulated-device"); | |
1341 | } | ||
1342 | else | ||
1343 | { | ||
1344 | ✗ | serial = g_usb_device_get_string_descriptor (usb_dev, | |
1345 | ✗ | g_usb_device_get_serial_number_index (usb_dev), | |
1346 | &error); | ||
1347 | |||
1348 | ✗ | if (serial && !g_str_has_suffix (serial, "B0")) | |
1349 | ✗ | fp_warn ("Device with serial %s not supported", serial); | |
1350 | ✗ | if (error) | |
1351 | { | ||
1352 | ✗ | g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (device)), | |
1353 | 0, 0, NULL); | ||
1354 | ✗ | goto err_close; | |
1355 | } | ||
1356 | } | ||
1357 | 1 | productid = g_usb_device_get_pid (usb_dev); | |
1358 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | switch (productid) |
1359 | { | ||
1360 | 1 | case 0x6496: | |
1361 | case 0x60A2: | ||
1362 | case 0x60A4: | ||
1363 | case 0x6014: | ||
1364 | case 0x6092: | ||
1365 | case 0x6094: | ||
1366 | case 0x609A: | ||
1367 | case 0x609C: | ||
1368 | case 0x60BC: | ||
1369 | case 0x6304: | ||
1370 | case 0x631C: | ||
1371 | case 0x633C: | ||
1372 | case 0x634C: | ||
1373 | case 0x6384: | ||
1374 | case 0x639C: | ||
1375 | case 0x63AC: | ||
1376 | case 0x63BC: | ||
1377 | case 0x63CC: | ||
1378 | case 0x650A: | ||
1379 | case 0x650C: | ||
1380 | case 0x6582: | ||
1381 | case 0x6A94: | ||
1382 | case 0x659A: | ||
1383 | 1 | self->max_enroll_stage = 12; | |
1384 | 1 | break; | |
1385 | |||
1386 | ✗ | default: | |
1387 | ✗ | self->max_enroll_stage = DEFAULT_ENROLL_SAMPLES; | |
1388 | ✗ | break; | |
1389 | } | ||
1390 | |||
1391 | 1 | fpi_device_set_nr_enroll_stages (device, self->max_enroll_stage); | |
1392 | |||
1393 | 1 | g_usb_device_close (usb_dev, NULL); | |
1394 | 1 | fpi_device_probe_complete (device, serial, NULL, error); | |
1395 | 1 | return; | |
1396 | ✗ | err_close: | |
1397 | |||
1398 | ✗ | g_usb_device_close (usb_dev, NULL); | |
1399 | ✗ | fpi_device_probe_complete (device, NULL, NULL, error); | |
1400 | |||
1401 | } | ||
1402 | |||
1403 | static void | ||
1404 | 1 | gx_fp_init (FpDevice *device) | |
1405 | { | ||
1406 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1407 | 1 | GError *error = NULL; | |
1408 | 1 | int ret = 0; | |
1409 | |||
1410 | 1 | self->max_stored_prints = FP_MAX_FINGERNUM; | |
1411 | 1 | self->is_power_button_shield_on = false; | |
1412 | |||
1413 | 1 | self->sensorcfg = g_new0 (gxfp_sensor_cfg_t, 1); | |
1414 | |||
1415 | 1 | ret = gx_proto_init_sensor_config (self->sensorcfg); | |
1416 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ret != 0) |
1417 | { | ||
1418 | ✗ | error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, "Init sensor failed"); | |
1419 | ✗ | fpi_device_open_complete (FP_DEVICE (self), error); | |
1420 | ✗ | return; | |
1421 | } | ||
1422 | 1 | self->sensorcfg->config[6] = self->max_enroll_stage; | |
1423 | |||
1424 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error)) |
1425 | { | ||
1426 | ✗ | fpi_device_open_complete (FP_DEVICE (self), error); | |
1427 | ✗ | return; | |
1428 | } | ||
1429 | |||
1430 | /* Claim usb interface */ | ||
1431 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error)) |
1432 | { | ||
1433 | ✗ | fpi_device_open_complete (FP_DEVICE (self), error); | |
1434 | ✗ | return; | |
1435 | } | ||
1436 | |||
1437 | 1 | self->task_ssm = fpi_ssm_new (device, fp_init_sm_run_state, | |
1438 | FP_INIT_NUM_STATES); | ||
1439 | |||
1440 | 1 | fpi_ssm_start (self->task_ssm, fp_init_ssm_done); | |
1441 | |||
1442 | } | ||
1443 | |||
1444 | static void | ||
1445 | 1 | gx_fp_release_interface (FpiDeviceGoodixMoc *self, | |
1446 | GError *error) | ||
1447 | { | ||
1448 | 2 | g_autoptr(GError) release_error = NULL; | |
1449 | |||
1450 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | g_clear_pointer (&self->sensorcfg, g_free); |
1451 | |||
1452 | /* Release usb interface */ | ||
1453 | 1 | g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)), | |
1454 | 0, 0, &release_error); | ||
1455 | /* Retain passed error if set, otherwise propagate error from release. */ | ||
1456 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (error == NULL) |
1457 | 1 | error = g_steal_pointer (&release_error); | |
1458 | |||
1459 | /* Notify close complete */ | ||
1460 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | fpi_device_close_complete (FP_DEVICE (self), error); |
1461 | |||
1462 | 1 | } | |
1463 | |||
1464 | static void | ||
1465 | ✗ | gx_fp_exit_cb (FpiDeviceGoodixMoc *self, | |
1466 | gxfp_cmd_response_t *resp, | ||
1467 | GError *error) | ||
1468 | { | ||
1469 | |||
1470 | |||
1471 | ✗ | if (resp->result >= GX_FAILED) | |
1472 | ✗ | fp_dbg ("Setting power button shield failed, result: 0x%x", resp->result); | |
1473 | ✗ | self->is_power_button_shield_on = false; | |
1474 | ✗ | gx_fp_release_interface (self, error); | |
1475 | ✗ | } | |
1476 | |||
1477 | static void | ||
1478 | 1 | gx_fp_exit (FpDevice *device) | |
1479 | { | ||
1480 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1481 | |||
1482 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (self->is_power_button_shield_on) |
1483 | { | ||
1484 | ✗ | goodix_sensor_cmd (self, | |
1485 | MOC_CMD0_PWR_BTN_SHIELD, | ||
1486 | MOC_CMD1_PWR_BTN_SHIELD_OFF, | ||
1487 | false, | ||
1488 | NULL, | ||
1489 | 0, | ||
1490 | gx_fp_exit_cb); | ||
1491 | } | ||
1492 | else | ||
1493 | { | ||
1494 | 1 | gx_fp_release_interface (self, NULL); | |
1495 | } | ||
1496 | |||
1497 | 1 | } | |
1498 | |||
1499 | |||
1500 | static void | ||
1501 | 2 | gx_fp_verify_identify (FpDevice *device) | |
1502 | { | ||
1503 | 2 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1504 | |||
1505 | 2 | self->task_ssm = fpi_ssm_new_full (device, fp_verify_sm_run_state, | |
1506 | FP_VERIFY_NUM_STATES, | ||
1507 | FP_VERIFY_PWR_BTN_SHIELD_OFF, | ||
1508 | "verify"); | ||
1509 | |||
1510 | 2 | fpi_ssm_start (self->task_ssm, fp_verify_ssm_done); | |
1511 | |||
1512 | 2 | } | |
1513 | |||
1514 | static void | ||
1515 | 1 | gx_fp_enroll (FpDevice *device) | |
1516 | { | ||
1517 | |||
1518 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1519 | |||
1520 | 1 | self->enroll_stage = 0; | |
1521 | |||
1522 | 1 | self->task_ssm = fpi_ssm_new_full (device, fp_enroll_sm_run_state, | |
1523 | FP_ENROLL_NUM_STATES, | ||
1524 | FP_ENROLL_PWR_BTN_SHIELD_OFF, | ||
1525 | "enroll"); | ||
1526 | |||
1527 | 1 | fpi_ssm_start (self->task_ssm, fp_enroll_ssm_done); | |
1528 | |||
1529 | 1 | } | |
1530 | |||
1531 | |||
1532 | static void | ||
1533 | 1 | gx_fp_template_list (FpDevice *device) | |
1534 | { | ||
1535 | |||
1536 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1537 | 1 | guint8 dummy[1] = { 0 }; | |
1538 | |||
1539 | 1 | G_DEBUG_HERE (); | |
1540 | |||
1541 | 1 | goodix_sensor_cmd (self, MOC_CMD0_GETFINGERLIST, MOC_CMD1_DEFAULT, | |
1542 | false, | ||
1543 | (const guint8 *) &dummy, | ||
1544 | 1, | ||
1545 | fp_template_list_cb); | ||
1546 | 1 | } | |
1547 | |||
1548 | |||
1549 | |||
1550 | static void | ||
1551 | 1 | gx_fp_template_delete (FpDevice *device) | |
1552 | { | ||
1553 | |||
1554 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1555 | 1 | FpPrint *print = NULL; | |
1556 | |||
1557 | 1 | g_autoptr(GVariant) data = NULL; | |
1558 | 1 | guint8 finger; | |
1559 | 1 | const guint8 *user_id; | |
1560 | 1 | gsize user_id_len = 0; | |
1561 | 1 | const guint8 *tid; | |
1562 | 1 | gsize tid_len = 0; | |
1563 | 1 | gsize payload_len = 0; | |
1564 |
1/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | g_autofree guint8 *payload = NULL; |
1565 | |||
1566 | 1 | fpi_device_get_delete_data (device, &print); | |
1567 | |||
1568 | 1 | g_object_get (print, "fpi-data", &data, NULL); | |
1569 | |||
1570 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!parse_print_data (data, &finger, &tid, &tid_len, &user_id, &user_id_len)) |
1571 | { | ||
1572 | ✗ | fpi_device_delete_complete (device, | |
1573 | fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); | ||
1574 | ✗ | return; | |
1575 | } | ||
1576 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!encode_finger_id (tid, tid_len, user_id, user_id_len, &payload, (guint16 *) &payload_len)) |
1577 | { | ||
1578 | ✗ | fpi_device_delete_complete (device, | |
1579 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
1580 | "encode_finger_id failed")); | ||
1581 | ✗ | return; | |
1582 | } | ||
1583 | |||
1584 | 1 | goodix_sensor_cmd (self, MOC_CMD0_DELETETEMPLATE, MOC_CMD1_DEFAULT, | |
1585 | false, | ||
1586 | (const guint8 *) payload, | ||
1587 | payload_len, | ||
1588 | fp_template_delete_cb); | ||
1589 | |||
1590 | } | ||
1591 | |||
1592 | static void | ||
1593 | 1 | gx_fp_template_delete_all (FpDevice *device) | |
1594 | { | ||
1595 | 1 | FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device); | |
1596 | |||
1597 | 1 | goodix_sensor_cmd (self, MOC_CMD0_DELETETEMPLATE, MOC_CMD1_DELETE_ALL, | |
1598 | false, | ||
1599 | NULL, | ||
1600 | 0, | ||
1601 | fp_template_delete_all_cb); | ||
1602 | |||
1603 | 1 | } | |
1604 | |||
1605 | static void | ||
1606 | 1 | fpi_device_goodixmoc_init (FpiDeviceGoodixMoc *self) | |
1607 | { | ||
1608 | |||
1609 | 1 | } | |
1610 | |||
1611 | static const FpIdEntry id_table[] = { | ||
1612 | { .vid = 0x27c6, .pid = 0x5840, }, | ||
1613 | { .vid = 0x27c6, .pid = 0x6014, }, | ||
1614 | { .vid = 0x27c6, .pid = 0x6092, }, | ||
1615 | { .vid = 0x27c6, .pid = 0x6094, }, | ||
1616 | { .vid = 0x27c6, .pid = 0x609A, }, | ||
1617 | { .vid = 0x27c6, .pid = 0x609C, }, | ||
1618 | { .vid = 0x27c6, .pid = 0x60A2, }, | ||
1619 | { .vid = 0x27c6, .pid = 0x60A4, }, | ||
1620 | { .vid = 0x27c6, .pid = 0x60BC, }, | ||
1621 | { .vid = 0x27c6, .pid = 0x6304, }, | ||
1622 | { .vid = 0x27c6, .pid = 0x631C, }, | ||
1623 | { .vid = 0x27c6, .pid = 0x633C, }, | ||
1624 | { .vid = 0x27c6, .pid = 0x634C, }, | ||
1625 | { .vid = 0x27c6, .pid = 0x6384, }, | ||
1626 | { .vid = 0x27c6, .pid = 0x639C, }, | ||
1627 | { .vid = 0x27c6, .pid = 0x63AC, }, | ||
1628 | { .vid = 0x27c6, .pid = 0x63BC, }, | ||
1629 | { .vid = 0x27c6, .pid = 0x63CC, }, | ||
1630 | { .vid = 0x27c6, .pid = 0x6496, }, | ||
1631 | { .vid = 0x27c6, .pid = 0x650A, }, | ||
1632 | { .vid = 0x27c6, .pid = 0x650C, }, | ||
1633 | { .vid = 0x27c6, .pid = 0x6582, }, | ||
1634 | { .vid = 0x27c6, .pid = 0x6584, }, | ||
1635 | { .vid = 0x27c6, .pid = 0x658C, }, | ||
1636 | { .vid = 0x27c6, .pid = 0x6592, }, | ||
1637 | { .vid = 0x27c6, .pid = 0x6594, }, | ||
1638 | { .vid = 0x27c6, .pid = 0x659A, }, | ||
1639 | { .vid = 0x27c6, .pid = 0x659C, }, | ||
1640 | { .vid = 0x27c6, .pid = 0x6A94, }, | ||
1641 | { .vid = 0x27c6, .pid = 0x6512, }, | ||
1642 | { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ | ||
1643 | }; | ||
1644 | |||
1645 | |||
1646 | static void | ||
1647 | 120 | fpi_device_goodixmoc_class_init (FpiDeviceGoodixMocClass *klass) | |
1648 | { | ||
1649 | 120 | FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); | |
1650 | |||
1651 | 120 | dev_class->id = "goodixmoc"; | |
1652 | 120 | dev_class->full_name = "Goodix MOC Fingerprint Sensor"; | |
1653 | 120 | dev_class->type = FP_DEVICE_TYPE_USB; | |
1654 | 120 | dev_class->scan_type = FP_SCAN_TYPE_PRESS; | |
1655 | 120 | dev_class->id_table = id_table; | |
1656 | 120 | dev_class->nr_enroll_stages = DEFAULT_ENROLL_SAMPLES; | |
1657 | 120 | dev_class->temp_hot_seconds = -1; | |
1658 | |||
1659 | 120 | dev_class->open = gx_fp_init; | |
1660 | 120 | dev_class->close = gx_fp_exit; | |
1661 | 120 | dev_class->probe = gx_fp_probe; | |
1662 | 120 | dev_class->enroll = gx_fp_enroll; | |
1663 | 120 | dev_class->delete = gx_fp_template_delete; | |
1664 | 120 | dev_class->clear_storage = gx_fp_template_delete_all; | |
1665 | 120 | dev_class->list = gx_fp_template_list; | |
1666 | 120 | dev_class->verify = gx_fp_verify_identify; | |
1667 | 120 | dev_class->identify = gx_fp_verify_identify; | |
1668 | |||
1669 | 120 | fpi_device_class_auto_initialize_features (dev_class); | |
1670 | 120 | dev_class->features |= FP_DEVICE_FEATURE_DUPLICATES_CHECK; | |
1671 | 120 | } | |
1672 |