Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (C) 2021 Elan Microelectronics Inc | ||
3 | * | ||
4 | * This library is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU Lesser General Public | ||
6 | * License as published by the Free Software Foundation; either | ||
7 | * version 2.1 of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This library is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * Lesser General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU Lesser General Public | ||
15 | * License along with this library; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
17 | */ | ||
18 | |||
19 | #define FP_COMPONENT "elanmoc" | ||
20 | |||
21 | #include "drivers_api.h" | ||
22 | #include "fpi-byte-reader.h" | ||
23 | #include "elanmoc.h" | ||
24 | |||
25 |
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 (FpiDeviceElanmoc, fpi_device_elanmoc, FP_TYPE_DEVICE) |
26 | |||
27 | static const FpIdEntry id_table[] = { | ||
28 | { .vid = 0x04f3, .pid = 0x0c7d, }, | ||
29 | { .vid = 0x04f3, .pid = 0x0c7e, }, | ||
30 | { .vid = 0x04f3, .pid = 0x0c82, }, | ||
31 | { .vid = 0x04f3, .pid = 0x0c88, }, | ||
32 | { .vid = 0x04f3, .pid = 0x0c8c, }, | ||
33 | { .vid = 0x04f3, .pid = 0x0c8d, }, | ||
34 | { .vid = 0x04f3, .pid = 0x0c99, }, | ||
35 | { .vid = 0x04f3, .pid = 0x0c9f, }, | ||
36 | { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ | ||
37 | }; | ||
38 | |||
39 | typedef void (*SynCmdMsgCallback) (FpiDeviceElanmoc *self, | ||
40 | uint8_t *buffer_in, | ||
41 | gsize length_in, | ||
42 | GError *error); | ||
43 | |||
44 | typedef struct | ||
45 | { | ||
46 | SynCmdMsgCallback callback; | ||
47 | } CommandData; | ||
48 | |||
49 | static uint8_t * | ||
50 | 38 | elanmoc_compose_cmd ( | |
51 | const struct elanmoc_cmd *cmd_info | ||
52 | ) | ||
53 | { | ||
54 | 76 | g_autofree uint8_t *cmd_buf = NULL; | |
55 | |||
56 | 38 | cmd_buf = g_new0 (uint8_t, cmd_info->cmd_len); | |
57 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 36 times.
|
38 | if(cmd_info->cmd_len < ELAN_MAX_HDR_LEN) |
58 | 2 | memcpy (cmd_buf, &cmd_info->cmd_header, cmd_info->cmd_len); | |
59 | else | ||
60 | 36 | memcpy (cmd_buf, &cmd_info->cmd_header, ELAN_MAX_HDR_LEN); | |
61 | |||
62 | 38 | return g_steal_pointer (&cmd_buf); | |
63 | } | ||
64 | |||
65 | static void | ||
66 | 4 | elanmoc_cmd_ack_cb (FpiDeviceElanmoc *self, | |
67 | uint8_t *buffer_in, | ||
68 | gsize length_in, | ||
69 | GError *error) | ||
70 | { | ||
71 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (error) |
72 | { | ||
73 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
74 | ✗ | return; | |
75 | } | ||
76 | |||
77 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if (length_in == 0) |
78 | { | ||
79 | 1 | fpi_ssm_next_state (self->task_ssm); | |
80 | 1 | return; | |
81 | } | ||
82 | |||
83 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
3 | if (buffer_in[0] != 0x40 && buffer_in[1] != 0x00 ) |
84 | { | ||
85 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
86 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
87 | "Can't get response!!")); | ||
88 | } | ||
89 | else | ||
90 | { | ||
91 | 3 | fpi_ssm_next_state (self->task_ssm); | |
92 | } | ||
93 | } | ||
94 | |||
95 | static void | ||
96 | 37 | fp_cmd_receive_cb (FpiUsbTransfer *transfer, | |
97 | FpDevice *device, | ||
98 | gpointer userdata, | ||
99 | GError *error) | ||
100 | { | ||
101 | 37 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (device); | |
102 | 37 | CommandData *data = userdata; | |
103 | 37 | int ssm_state = 0; | |
104 | |||
105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if (error) |
106 | { | ||
107 | ✗ | fpi_ssm_mark_failed (transfer->ssm, error); | |
108 | ✗ | return; | |
109 | } | ||
110 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if (data == NULL) |
111 | { | ||
112 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
113 | fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); | ||
114 | ✗ | return; | |
115 | } | ||
116 | 37 | ssm_state = fpi_ssm_get_cur_state (transfer->ssm); | |
117 | |||
118 | /* skip zero length package */ | ||
119 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if (transfer->actual_length == 0) |
120 | { | ||
121 | ✗ | fpi_ssm_jump_to_state (transfer->ssm, ssm_state); | |
122 | ✗ | return; | |
123 | } | ||
124 | |||
125 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | if (data->callback) |
126 | 37 | data->callback (self, transfer->buffer, transfer->actual_length, NULL); | |
127 | |||
128 | 37 | fpi_ssm_mark_completed (transfer->ssm); | |
129 | } | ||
130 | |||
131 | typedef enum { | ||
132 | FP_CMD_SEND = 0, | ||
133 | FP_CMD_GET, | ||
134 | FP_CMD_NUM_STATES, | ||
135 | } FpCmdState; | ||
136 | |||
137 | static void | ||
138 | 76 | fp_cmd_run_state (FpiSsm *ssm, | |
139 | FpDevice *dev) | ||
140 | { | ||
141 | 76 | FpiUsbTransfer *transfer; | |
142 | 76 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (dev); | |
143 | |||
144 |
2/3✓ Branch 1 taken 38 times.
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
|
76 | switch (fpi_ssm_get_cur_state (ssm)) |
145 | { | ||
146 | 38 | case FP_CMD_SEND: | |
147 |
1/2✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
|
38 | if (self->cmd_transfer) |
148 | { | ||
149 | 38 | self->cmd_transfer->ssm = ssm; | |
150 | 38 | fpi_usb_transfer_submit (g_steal_pointer (&self->cmd_transfer), | |
151 | ELAN_MOC_CMD_TIMEOUT, | ||
152 | NULL, | ||
153 | fpi_ssm_usb_transfer_cb, | ||
154 | NULL); | ||
155 | } | ||
156 | else | ||
157 | { | ||
158 | ✗ | fpi_ssm_next_state (ssm); | |
159 | } | ||
160 | break; | ||
161 | |||
162 | 38 | case FP_CMD_GET: | |
163 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 37 times.
|
38 | if (self->cmd_len_in == 0) |
164 | { | ||
165 | 1 | CommandData *data = fpi_ssm_get_data (ssm); | |
166 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (data->callback) |
167 | 1 | data->callback (self, NULL, 0, 0); | |
168 | 1 | fpi_ssm_mark_completed (ssm); | |
169 | 1 | return; | |
170 | } | ||
171 | 37 | transfer = fpi_usb_transfer_new (dev); | |
172 | 37 | transfer->ssm = ssm; | |
173 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 13 times.
|
61 | fpi_usb_transfer_fill_bulk (transfer, self->cmd_cancelable ? ELAN_EP_MOC_CMD_IN : ELAN_EP_CMD_IN, self->cmd_len_in); |
174 | 37 | fpi_usb_transfer_submit (transfer, | |
175 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 13 times.
|
37 | self->cmd_cancelable ? 0 : ELAN_MOC_CMD_TIMEOUT, |
176 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 24 times.
|
37 | self->cmd_cancelable ? fpi_device_get_cancellable (dev) : NULL, |
177 | fp_cmd_receive_cb, | ||
178 | fpi_ssm_get_data (ssm)); | ||
179 | 37 | break; | |
180 | |||
181 | } | ||
182 | |||
183 | } | ||
184 | |||
185 | static void | ||
186 | 38 | fp_cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) | |
187 | { | ||
188 | 38 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (dev); | |
189 | 38 | CommandData *data = fpi_ssm_get_data (ssm); | |
190 | |||
191 | 38 | self->cmd_ssm = NULL; | |
192 | |||
193 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
38 | if (error) |
194 | { | ||
195 | ✗ | if (data->callback) | |
196 | ✗ | data->callback (self, NULL, 0, error); | |
197 | else | ||
198 | ✗ | g_error_free (error); | |
199 | } | ||
200 | 38 | } | |
201 | |||
202 | static void | ||
203 | 39 | fp_cmd_ssm_done_data_free (CommandData *data) | |
204 | { | ||
205 | 39 | g_free (data); | |
206 | 39 | } | |
207 | |||
208 | static void | ||
209 | 38 | elanmoc_get_cmd (FpDevice *device, guint8 *buffer_out, | |
210 | gsize length_out, gsize length_in, gboolean cancelable, SynCmdMsgCallback callback) | ||
211 | { | ||
212 | 38 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (device); | |
213 | |||
214 | 76 | g_autoptr(FpiUsbTransfer) transfer = NULL; | |
215 | 38 | CommandData *data = g_new0 (CommandData, 1); | |
216 | |||
217 | 38 | transfer = fpi_usb_transfer_new (device); | |
218 | 38 | transfer->short_is_error = TRUE; | |
219 | 38 | fpi_usb_transfer_fill_bulk_full (transfer, ELAN_EP_CMD_OUT, buffer_out, | |
220 | length_out, g_free); | ||
221 | 38 | data->callback = callback; | |
222 | |||
223 | 38 | self->cmd_transfer = g_steal_pointer (&transfer); | |
224 | 38 | self->cmd_len_in = length_in; | |
225 | 38 | self->cmd_cancelable = cancelable; | |
226 | |||
227 | 38 | self->cmd_ssm = fpi_ssm_new (FP_DEVICE (self), | |
228 | fp_cmd_run_state, | ||
229 | FP_CMD_NUM_STATES); | ||
230 | |||
231 | 38 | fpi_ssm_set_data (self->cmd_ssm, data, (GDestroyNotify) fp_cmd_ssm_done_data_free); | |
232 | |||
233 | 38 | fpi_ssm_start (self->cmd_ssm, fp_cmd_ssm_done); | |
234 | 38 | } | |
235 | |||
236 | enum enroll_states { | ||
237 | ENROLL_RSP_RETRY, | ||
238 | ENROLL_RSP_ENROLL_REPORT, | ||
239 | ENROLL_RSP_ENROLL_OK, | ||
240 | ENROLL_RSP_ENROLL_CANCEL_REPORT, | ||
241 | ENROLL_NUM_STATES, | ||
242 | }; | ||
243 | |||
244 | static void | ||
245 | 12 | enroll_status_report (FpiDeviceElanmoc *self, int enroll_status_id, | |
246 | int data, GError *error) | ||
247 | { | ||
248 | 12 | FpDevice *device = FP_DEVICE (self); | |
249 | |||
250 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (error) |
251 | { | ||
252 | ✗ | fpi_device_enroll_complete (device, NULL, error); | |
253 | ✗ | return; | |
254 | } | ||
255 | |||
256 |
3/5✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
12 | switch (enroll_status_id) |
257 | { | ||
258 | 2 | case ENROLL_RSP_RETRY: | |
259 | { | ||
260 | 2 | fpi_device_enroll_progress (device, self->num_frames, NULL, | |
261 | fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER)); | ||
262 | 2 | break; | |
263 | } | ||
264 | |||
265 | 9 | case ENROLL_RSP_ENROLL_REPORT: | |
266 | { | ||
267 | 9 | fpi_device_enroll_progress (device, self->num_frames, NULL, NULL); | |
268 | 9 | break; | |
269 | } | ||
270 | |||
271 | 1 | case ENROLL_RSP_ENROLL_OK: | |
272 | { | ||
273 | 1 | FpPrint *print = NULL; | |
274 | 1 | fp_info ("Enrollment was successful!"); | |
275 | 1 | fpi_device_get_enroll_data (device, &print); | |
276 | 1 | fpi_device_enroll_complete (device, g_object_ref (print), NULL); | |
277 | 1 | break; | |
278 | } | ||
279 | |||
280 | ✗ | case ENROLL_RSP_ENROLL_CANCEL_REPORT: | |
281 | { | ||
282 | ✗ | fpi_device_enroll_complete (device, NULL, | |
283 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
284 | "Enrollment failed (%d) (ENROLL_RSP_ENROLL_CANCEL_REPORT)", | ||
285 | data)); | ||
286 | } | ||
287 | } | ||
288 | } | ||
289 | |||
290 | static void | ||
291 | 3 | elanmoc_get_enrolled_cb (FpiDeviceElanmoc *self, | |
292 | uint8_t *buffer_in, | ||
293 | gsize length_in, | ||
294 | GError *error) | ||
295 | { | ||
296 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (error) |
297 | { | ||
298 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
299 | ✗ | return; | |
300 | } | ||
301 | |||
302 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (buffer_in[0] != 0x40) |
303 | { | ||
304 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
305 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
306 | "Can't get response!!")); | ||
307 | } | ||
308 | else | ||
309 | { | ||
310 | 3 | fp_info ("elanmoc Current enrolled fingers in the Chipset: %d (0x%.2X 0x%.2X)", buffer_in[1], | |
311 | buffer_in[0], | ||
312 | buffer_in[1]); | ||
313 | 3 | self->curr_enrolled = buffer_in[1]; | |
314 | 3 | fpi_ssm_next_state (self->task_ssm); | |
315 | } | ||
316 | } | ||
317 | |||
318 | static void | ||
319 | 1 | elanmoc_reenroll_cb (FpiDeviceElanmoc *self, | |
320 | uint8_t *buffer_in, | ||
321 | gsize length_in, | ||
322 | GError *error) | ||
323 | { | ||
324 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
325 | { | ||
326 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
327 | ✗ | return; | |
328 | } | ||
329 | |||
330 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (buffer_in[0] != 0x40) |
331 | { | ||
332 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
333 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
334 | "Can't get response!!")); | ||
335 | } | ||
336 | else | ||
337 | { | ||
338 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | if ((self->curr_enrolled == (ELAN_MAX_ENROLL_NUM + 1)) && (buffer_in[1] == 0x00)) |
339 | { | ||
340 | ✗ | fp_warn ("elanmoc_reenroll_cb over enroll max"); | |
341 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
342 | fpi_device_error_new (FP_DEVICE_ERROR_DATA_FULL)); | ||
343 | ✗ | return; | |
344 | } | ||
345 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (buffer_in[1] == 0x00) |
346 | ✗ | fp_info ("##### Normal Enrollment Case! #####"); | |
347 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | else if (buffer_in[1] == 0x01) |
348 | 1 | fp_info ("##### Re-Enrollment Case! #####"); | |
349 | 1 | self->num_frames = 0; | |
350 | 1 | fpi_ssm_next_state (self->task_ssm); | |
351 | } | ||
352 | } | ||
353 | |||
354 | static void | ||
355 | 11 | elanmoc_enroll_cb (FpiDeviceElanmoc *self, | |
356 | uint8_t *buffer_in, | ||
357 | gsize length_in, | ||
358 | GError *error) | ||
359 | { | ||
360 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | if (error) |
361 | { | ||
362 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
363 | ✗ | return; | |
364 | } | ||
365 | |||
366 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | if (buffer_in[0] != 0x40) |
367 | { | ||
368 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
369 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
370 | "Can't get response!!")); | ||
371 | } | ||
372 | else | ||
373 | { | ||
374 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
|
11 | if (buffer_in[1] == ELAN_MSG_OK) |
375 | { | ||
376 | 9 | self->num_frames += 1; | |
377 | 9 | enroll_status_report (self, ENROLL_RSP_ENROLL_REPORT, self->num_frames, NULL); | |
378 | } | ||
379 | else | ||
380 | { | ||
381 | 2 | enroll_status_report (self, ENROLL_RSP_RETRY, self->num_frames, NULL); | |
382 | } | ||
383 | |||
384 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
11 | if (self->num_frames == self->max_moc_enroll_time && buffer_in[1] == ELAN_MSG_OK) |
385 | 1 | fpi_ssm_next_state (self->task_ssm); | |
386 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | else if (self->num_frames < self->max_moc_enroll_time) |
387 | 10 | fpi_ssm_jump_to_state (self->task_ssm, MOC_ENROLL_WAIT_FINGER); | |
388 | else | ||
389 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
390 | } | ||
391 | } | ||
392 | |||
393 | static void | ||
394 | 1 | elanmoc_commit_cb (FpiDeviceElanmoc *self, | |
395 | uint8_t *buffer_in, | ||
396 | gsize length_in, | ||
397 | GError *error) | ||
398 | { | ||
399 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
400 | { | ||
401 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
402 | ✗ | return; | |
403 | } | ||
404 | |||
405 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (length_in == 0) |
406 | { | ||
407 | ✗ | fpi_ssm_next_state (self->task_ssm); | |
408 | ✗ | return; | |
409 | } | ||
410 | |||
411 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | if (buffer_in[0] != 0x40 && buffer_in[1] != 0x00 ) |
412 | { | ||
413 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
414 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
415 | "Can't get response!!")); | ||
416 | } | ||
417 | else | ||
418 | { | ||
419 | 1 | fp_info ("elanmoc_commit_cb success"); | |
420 | 1 | enroll_status_report (self, ENROLL_RSP_ENROLL_OK, self->num_frames, NULL); | |
421 | 1 | fpi_ssm_next_state (self->task_ssm); | |
422 | } | ||
423 | } | ||
424 | |||
425 | static void | ||
426 | 14 | elan_enroll_run_state (FpiSsm *ssm, FpDevice *dev) | |
427 | { | ||
428 | 14 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (dev); | |
429 | 14 | guint8 *cmd_buf = NULL; | |
430 | 14 | guint8 *data = NULL; | |
431 | |||
432 |
4/5✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
14 | switch (fpi_ssm_get_cur_state (ssm)) |
433 | { | ||
434 | 1 | case MOC_ENROLL_GET_ENROLLED_NUM: | |
435 | 1 | cmd_buf = elanmoc_compose_cmd (&enrolled_number_cmd); | |
436 | 1 | elanmoc_get_cmd (dev, cmd_buf, enrolled_number_cmd.cmd_len, enrolled_number_cmd.resp_len, 0, elanmoc_get_enrolled_cb); | |
437 | 1 | break; | |
438 | |||
439 | 1 | case MOC_ENROLL_REENROLL_CHECK: | |
440 | 1 | data = fpi_ssm_get_data (ssm); | |
441 | 1 | cmd_buf = elanmoc_compose_cmd (&elanmoc_check_reenroll_cmd); | |
442 | 1 | memcpy (cmd_buf + 3, data, ELAN_USERDATE_SIZE); | |
443 | 1 | elanmoc_get_cmd (dev, cmd_buf, elanmoc_check_reenroll_cmd.cmd_len, elanmoc_check_reenroll_cmd.resp_len, 0, elanmoc_reenroll_cb); | |
444 | 1 | break; | |
445 | |||
446 | 11 | case MOC_ENROLL_WAIT_FINGER: | |
447 | 11 | cmd_buf = elanmoc_compose_cmd (&elanmoc_enroll_cmd); | |
448 | 11 | cmd_buf[3] = self->curr_enrolled; | |
449 | 11 | cmd_buf[4] = self->max_moc_enroll_time; | |
450 | 11 | cmd_buf[5] = self->num_frames; | |
451 | 11 | elanmoc_get_cmd (dev, cmd_buf, elanmoc_enroll_cmd.cmd_len, elanmoc_enroll_cmd.resp_len, 1, elanmoc_enroll_cb); | |
452 | 11 | break; | |
453 | |||
454 | 1 | case MOC_ENROLL_COMMIT_RESULT: | |
455 | 1 | data = fpi_ssm_get_data (ssm); | |
456 | 1 | cmd_buf = elanmoc_compose_cmd (&elanmoc_enroll_commit_cmd); | |
457 | 1 | memcpy (cmd_buf + 5, data, ELAN_USERDATE_SIZE); | |
458 | 1 | elanmoc_get_cmd (dev, cmd_buf, elanmoc_enroll_commit_cmd.cmd_len, elanmoc_enroll_commit_cmd.resp_len, 0, elanmoc_commit_cb); | |
459 | 1 | break; | |
460 | } | ||
461 | 14 | } | |
462 | |||
463 | static void | ||
464 | 5 | task_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) | |
465 | { | ||
466 | 5 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (dev); | |
467 | |||
468 | 5 | self->task_ssm = NULL; | |
469 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | g_clear_pointer (&self->list_result, g_ptr_array_unref); |
470 | |||
471 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (error) |
472 | ✗ | fpi_device_action_error (dev, error); | |
473 | 5 | } | |
474 | |||
475 | static FpPrint * | ||
476 | 3 | create_print_from_response (FpiDeviceElanmoc *self, | |
477 | uint8_t *buffer_in, | ||
478 | gsize length_in, | ||
479 | GError **error) | ||
480 | { | ||
481 | 3 | FpPrint *print; | |
482 | 3 | GVariant *data; | |
483 | 3 | GVariant *uid; | |
484 | 6 | g_autofree gchar *userid = NULL; | |
485 | 3 | g_autofree gchar *userid_safe = NULL; | |
486 | 3 | int userid_len = 0; | |
487 | |||
488 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (buffer_in[0] != 0x43) |
489 | { | ||
490 | ✗ | g_propagate_error (error, | |
491 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
492 | "Can't get response!!")); | ||
493 | ✗ | return NULL; | |
494 | } | ||
495 | |||
496 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (buffer_in[1] != ELAN_MSG_OK) |
497 | { | ||
498 | ✗ | g_propagate_error (error, | |
499 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
500 | "Device returned error %d rather than print!", buffer_in[1])); | ||
501 | ✗ | return NULL; | |
502 | } | ||
503 | |||
504 | 3 | userid_len = buffer_in[4]; | |
505 | |||
506 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (userid_len > length_in - 5) |
507 | { | ||
508 | ✗ | g_propagate_error (error, | |
509 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
510 | "Packet too short for payload length!")); | ||
511 | ✗ | return NULL; | |
512 | } | ||
513 | |||
514 | 3 | userid = g_memdup2 (&buffer_in[5], userid_len); | |
515 | 3 | userid_safe = g_strndup ((const char *) &buffer_in[5], userid_len); | |
516 | 3 | print = fp_print_new (FP_DEVICE (self)); | |
517 | 3 | uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, userid, userid_len, 1); | |
518 | |||
519 | /* The first two bytes are meant to store a UUID, | ||
520 | * but will always be zero for prints created by libfprint. | ||
521 | */ | ||
522 | 6 | data = g_variant_new ("(yy@ay)", | |
523 | 3 | buffer_in[2], | |
524 | 3 | buffer_in[3], | |
525 | uid); | ||
526 | |||
527 | 3 | fpi_print_set_type (print, FPI_PRINT_RAW); | |
528 | 3 | fpi_print_set_device_stored (print, TRUE); | |
529 | 3 | g_object_set (print, "fpi-data", data, NULL); | |
530 | 3 | g_object_set (print, "description", userid_safe, NULL); | |
531 | |||
532 | 3 | fpi_print_fill_from_user_id (print, userid_safe); | |
533 | |||
534 | 3 | return print; | |
535 | } | ||
536 | |||
537 | static void | ||
538 | 10 | elanmoc_get_userid_cb (FpiDeviceElanmoc *self, | |
539 | uint8_t *buffer_in, | ||
540 | gsize length_in, | ||
541 | GError *error) | ||
542 | { | ||
543 | 10 | FpPrint *print; | |
544 | |||
545 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (error) |
546 | { | ||
547 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
548 | ✗ | return; | |
549 | } | ||
550 | |||
551 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (buffer_in[0] != 0x43) |
552 | { | ||
553 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
554 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
555 | "Can't get response!!")); | ||
556 | ✗ | return; | |
557 | } | ||
558 | |||
559 | 10 | self->list_index++; | |
560 | |||
561 | /* Skip 0xfe messages */ | ||
562 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
|
10 | if (buffer_in[1] != 0xfe) |
563 | { | ||
564 | 1 | print = create_print_from_response (self, buffer_in, length_in, &error); | |
565 | |||
566 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!print) |
567 | { | ||
568 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
569 | ✗ | return; | |
570 | } | ||
571 | |||
572 | 1 | g_ptr_array_add (self->list_result, g_object_ref_sink (print)); | |
573 | } | ||
574 | |||
575 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
|
10 | if(self->list_index <= ELAN_MAX_ENROLL_NUM) |
576 | { | ||
577 | 9 | fpi_ssm_jump_to_state (self->task_ssm, MOC_LIST_GET_FINGER); | |
578 | } | ||
579 | else | ||
580 | { | ||
581 | 1 | fpi_device_list_complete (FP_DEVICE (self), g_steal_pointer (&self->list_result), NULL); | |
582 | 1 | fpi_ssm_next_state (self->task_ssm); | |
583 | } | ||
584 | } | ||
585 | |||
586 | static void | ||
587 | 11 | elan_list_run_state (FpiSsm *ssm, FpDevice *dev) | |
588 | { | ||
589 | 11 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (dev); | |
590 | 11 | guint8 *cmd_buf = NULL; | |
591 | |||
592 |
2/3✓ Branch 1 taken 1 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
11 | switch (fpi_ssm_get_cur_state (ssm)) |
593 | { | ||
594 | 1 | case MOC_LIST_GET_ENROLLED: | |
595 | 1 | cmd_buf = elanmoc_compose_cmd (&enrolled_number_cmd); | |
596 | 1 | elanmoc_get_cmd (dev, cmd_buf, enrolled_number_cmd.cmd_len, enrolled_number_cmd.resp_len, 0, elanmoc_get_enrolled_cb); | |
597 | 1 | self->list_index = 0; | |
598 | 1 | break; | |
599 | |||
600 | 10 | case MOC_LIST_GET_FINGER: | |
601 | 10 | cmd_buf = elanmoc_compose_cmd (&elanmoc_get_userid_cmd); | |
602 | 10 | cmd_buf[2] = self->list_index; | |
603 | 10 | elanmoc_get_cmd (dev, cmd_buf, elanmoc_get_userid_cmd.cmd_len, elanmoc_get_userid_cmd.resp_len, 0, elanmoc_get_userid_cb); | |
604 | 10 | break; | |
605 | } | ||
606 | 11 | } | |
607 | |||
608 | static void | ||
609 | 1 | elanmoc_list (FpDevice *device) | |
610 | { | ||
611 | 1 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (device); | |
612 | |||
613 | 1 | self->list_result = g_ptr_array_new_with_free_func (g_object_unref); | |
614 | 1 | self->task_ssm = fpi_ssm_new (FP_DEVICE (self), | |
615 | elan_list_run_state, | ||
616 | MOC_LIST_NUM_STATES); | ||
617 | 1 | fpi_ssm_start (self->task_ssm, task_ssm_done); | |
618 | 1 | } | |
619 | |||
620 | enum verify_status { | ||
621 | RSP_VERIFY_FAIL, | ||
622 | RSP_VERIFY_OK, | ||
623 | RSP_VERIFY_STATES, | ||
624 | }; | ||
625 | |||
626 | static void | ||
627 | 2 | elanmoc_match_report_cb (FpiDeviceElanmoc *self, | |
628 | uint8_t *buffer_in, | ||
629 | gsize length_in, | ||
630 | GError *error) | ||
631 | { | ||
632 | 2 | FpDevice *device = FP_DEVICE (self); | |
633 | 2 | FpPrint *print = NULL; | |
634 | 2 | FpPrint *verify_print = NULL; | |
635 | 2 | GPtrArray *prints; | |
636 | 2 | gboolean found = FALSE; | |
637 | 2 | guint index; | |
638 | |||
639 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (error) |
640 | { | ||
641 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
642 | ✗ | return; | |
643 | } | ||
644 | |||
645 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (buffer_in[0] != 0x43) |
646 | { | ||
647 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
648 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
649 | "Can't get response!!")); | ||
650 | ✗ | return; | |
651 | } | ||
652 | |||
653 | 2 | print = create_print_from_response (self, buffer_in, length_in, &error); | |
654 | |||
655 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!print) |
656 | { | ||
657 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
658 | ✗ | return; | |
659 | } | ||
660 | |||
661 | 2 | fp_info ("Verify/Identify successful for: %s", fp_print_get_description (print)); | |
662 | |||
663 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
|
2 | if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_IDENTIFY) |
664 | { | ||
665 | 1 | fpi_device_get_identify_data (device, &prints); | |
666 | 1 | found = g_ptr_array_find_with_equal_func (prints, | |
667 | print, | ||
668 | (GEqualFunc) fp_print_equal, | ||
669 | &index); | ||
670 | |||
671 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (found) |
672 | 1 | fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL); | |
673 | else | ||
674 | ✗ | fpi_device_identify_report (device, NULL, print, NULL); | |
675 | |||
676 | 1 | fpi_device_identify_complete (device, NULL); | |
677 | } | ||
678 | else | ||
679 | { | ||
680 | 1 | fpi_device_get_verify_data (device, &verify_print); | |
681 | |||
682 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if (fp_print_equal (verify_print, print)) |
683 | 1 | fpi_device_verify_report (device, FPI_MATCH_SUCCESS, print, NULL); | |
684 | else | ||
685 | ✗ | fpi_device_verify_report (device, FPI_MATCH_FAIL, print, NULL); | |
686 | 1 | fpi_device_verify_complete (device, NULL); | |
687 | } | ||
688 | } | ||
689 | |||
690 | static void | ||
691 | 2 | identify_status_report (FpiDeviceElanmoc *self, int verify_status_id, | |
692 | int data, GError *error) | ||
693 | { | ||
694 | 2 | FpDevice *device = FP_DEVICE (self); | |
695 | 2 | guint8 *cmd_buf = NULL; | |
696 | |||
697 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (error) |
698 | { | ||
699 | ✗ | if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY) | |
700 | ✗ | fpi_device_verify_complete (device, error); | |
701 | else | ||
702 | ✗ | fpi_device_identify_complete (device, error); | |
703 | ✗ | return; | |
704 | } | ||
705 | |||
706 |
1/3✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | switch (verify_status_id) |
707 | { | ||
708 | ✗ | case RSP_VERIFY_FAIL: | |
709 | { | ||
710 | ✗ | if (data == ELAN_MSG_VERIFY_ERR) | |
711 | { | ||
712 | ✗ | if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY) | |
713 | { | ||
714 | ✗ | fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL); | |
715 | ✗ | fpi_device_verify_complete (device, NULL); | |
716 | } | ||
717 | else | ||
718 | { | ||
719 | ✗ | fpi_device_identify_report (device, NULL, NULL, NULL); | |
720 | ✗ | fpi_device_identify_complete (device, NULL); | |
721 | } | ||
722 | } | ||
723 | else | ||
724 | { | ||
725 | ✗ | GError *retry_error; | |
726 | |||
727 | ✗ | switch (data) | |
728 | { | ||
729 | ✗ | case ELAN_MSG_TOO_HIGH: | |
730 | case ELAN_MSG_TOO_LOW: | ||
731 | case ELAN_MSG_TOO_RIGHT: | ||
732 | case ELAN_MSG_TOO_LEFT: | ||
733 | ✗ | retry_error = fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER); | |
734 | ✗ | break; | |
735 | |||
736 | ✗ | default: | |
737 | ✗ | retry_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); | |
738 | } | ||
739 | |||
740 | ✗ | if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY) | |
741 | { | ||
742 | ✗ | fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL, retry_error); | |
743 | ✗ | fpi_device_verify_complete (device, NULL); | |
744 | } | ||
745 | else | ||
746 | { | ||
747 | ✗ | fpi_device_identify_report (device, NULL, NULL, retry_error); | |
748 | ✗ | fpi_device_identify_complete (device, NULL); | |
749 | } | ||
750 | } | ||
751 | break; | ||
752 | } | ||
753 | |||
754 | 2 | case RSP_VERIFY_OK: | |
755 | { | ||
756 | 2 | fp_dbg ("Verify was successful! for user: %d mesg_code: %d ", data, verify_status_id); | |
757 | 2 | cmd_buf = elanmoc_compose_cmd (&elanmoc_get_userid_cmd); | |
758 | 2 | cmd_buf[2] = data; | |
759 | 2 | elanmoc_get_cmd (device, cmd_buf, elanmoc_get_userid_cmd.cmd_len, elanmoc_get_userid_cmd.resp_len, 0, elanmoc_match_report_cb); | |
760 | 2 | break; | |
761 | } | ||
762 | } | ||
763 | } | ||
764 | |||
765 | enum identify_states { | ||
766 | IDENTIFY_SET_MODE, | ||
767 | IDENTIFY_WAIT_FINGER, | ||
768 | IDENTIFY_NUM_STATES, | ||
769 | }; | ||
770 | |||
771 | static void | ||
772 | 2 | elanmoc_identify_cb (FpiDeviceElanmoc *self, | |
773 | uint8_t *buffer_in, | ||
774 | gsize length_in, | ||
775 | GError *error) | ||
776 | { | ||
777 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (error) |
778 | { | ||
779 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
780 | ✗ | return; | |
781 | } | ||
782 | |||
783 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (buffer_in[1] == ELAN_MSG_VERIFY_ERR) |
784 | ✗ | identify_status_report (self, RSP_VERIFY_FAIL, | |
785 | buffer_in[1], error); | ||
786 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | else if (buffer_in[1] <= ELAN_MAX_ENROLL_NUM) |
787 | 2 | identify_status_report (self, RSP_VERIFY_OK, buffer_in[1], error); | |
788 | else | ||
789 | ✗ | identify_status_report (self, RSP_VERIFY_FAIL, buffer_in[1], error); | |
790 | 2 | fpi_ssm_next_state (self->task_ssm); | |
791 | |||
792 | } | ||
793 | |||
794 | static void | ||
795 | 4 | elan_identify_run_state (FpiSsm *ssm, FpDevice *dev) | |
796 | { | ||
797 | 4 | guint8 *cmd_buf = NULL; | |
798 | |||
799 | 4 | fp_info ("elanmoc %s ", __func__); | |
800 |
2/3✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
4 | switch (fpi_ssm_get_cur_state (ssm)) |
801 | { | ||
802 | 2 | case IDENTIFY_SET_MODE: | |
803 | 2 | fp_info ("elanmoc %s IDENTIFY_SET_MODE", __func__); | |
804 | 2 | cmd_buf = elanmoc_compose_cmd (&elanmoc_set_mod_cmd); | |
805 | 2 | cmd_buf[3] = 0x03; | |
806 | 2 | elanmoc_get_cmd (dev, cmd_buf, elanmoc_set_mod_cmd.cmd_len, elanmoc_set_mod_cmd.resp_len, 0, elanmoc_cmd_ack_cb); | |
807 | 2 | break; | |
808 | |||
809 | 2 | case IDENTIFY_WAIT_FINGER: | |
810 | 2 | fp_info ("elanmoc %s VERIFY_WAIT_FINGER", __func__); | |
811 | 2 | cmd_buf = elanmoc_compose_cmd (&elanmoc_verify_cmd); | |
812 | 2 | elanmoc_get_cmd (dev, cmd_buf, elanmoc_verify_cmd.cmd_len, elanmoc_verify_cmd.resp_len, 1, elanmoc_identify_cb); | |
813 | 2 | break; | |
814 | } | ||
815 | 4 | } | |
816 | |||
817 | static void | ||
818 | 1 | elanmoc_enroll (FpDevice *device) | |
819 | { | ||
820 | 1 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (device); | |
821 | 1 | FpPrint *print = NULL; | |
822 | 1 | GVariant *data = NULL; | |
823 | 1 | GVariant *uid = NULL; | |
824 | 2 | g_autofree gchar *user_id = NULL; | |
825 | 1 | gsize user_id_len; | |
826 | 1 | guint8 *userdata = g_malloc0 (ELAN_USERDATE_SIZE); | |
827 | |||
828 | 1 | fpi_device_get_enroll_data (device, &print); | |
829 | 1 | user_id = fpi_print_generate_user_id (print); | |
830 | 1 | user_id_len = strlen (user_id); | |
831 | 1 | user_id_len = MIN (ELAN_MAX_USER_ID_LEN, user_id_len); | |
832 | |||
833 | 1 | uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, | |
834 | user_id, | ||
835 | user_id_len, 1); | ||
836 | |||
837 | 1 | data = g_variant_new ("(yy@ay)", | |
838 | 0, 0, | ||
839 | uid); | ||
840 | |||
841 | 1 | fpi_print_set_type (print, FPI_PRINT_RAW); | |
842 | 1 | fpi_print_set_device_stored (print, TRUE); | |
843 | 1 | g_object_set (print, "fpi-data", data, NULL); | |
844 | 1 | g_object_set (print, "description", user_id, NULL); | |
845 | |||
846 | 1 | userdata[0] = 0; | |
847 | 1 | userdata[1] = 0; | |
848 | 1 | userdata[2] = user_id_len; | |
849 | |||
850 | 1 | memcpy (userdata + 3, user_id, user_id_len); | |
851 | 1 | self->task_ssm = fpi_ssm_new (FP_DEVICE (self), | |
852 | elan_enroll_run_state, | ||
853 | MOC_ENROLL_NUM_STATES); | ||
854 | 1 | fpi_ssm_set_data (self->task_ssm, userdata, (GDestroyNotify) fp_cmd_ssm_done_data_free); | |
855 | 1 | fpi_ssm_start (self->task_ssm, task_ssm_done); | |
856 | 1 | } | |
857 | |||
858 | static void | ||
859 | 1 | elanmoc_delete_cb (FpiDeviceElanmoc *self, | |
860 | uint8_t *buffer_in, | ||
861 | gsize length_in, | ||
862 | GError *error) | ||
863 | { | ||
864 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
865 | { | ||
866 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
867 | ✗ | return; | |
868 | } | ||
869 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | if (buffer_in[0] != 0x40 && buffer_in[1] != 0x00) |
870 | { | ||
871 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
872 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
873 | "Can't get response!!")); | ||
874 | } | ||
875 | else | ||
876 | { | ||
877 | 1 | fpi_device_delete_complete (FP_DEVICE (self), NULL); | |
878 | 1 | fpi_ssm_next_state (self->task_ssm); | |
879 | } | ||
880 | } | ||
881 | |||
882 | static void | ||
883 | 1 | elan_delete_run_state (FpiSsm *ssm, FpDevice *dev) | |
884 | { | ||
885 | 1 | guint8 *cmd_buf = NULL; | |
886 | 1 | guint8 *data = fpi_ssm_get_data (ssm); | |
887 | |||
888 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | switch (fpi_ssm_get_cur_state (ssm)) |
889 | { | ||
890 | 1 | case DELETE_SEND_CMD: | |
891 | 1 | cmd_buf = elanmoc_compose_cmd (&elanmoc_delete_cmd); | |
892 | 1 | memcpy (cmd_buf + 3, data, ELAN_USERDATE_SIZE); | |
893 | 1 | elanmoc_get_cmd (dev, cmd_buf, elanmoc_delete_cmd.cmd_len, elanmoc_delete_cmd.resp_len, 0, elanmoc_delete_cb); | |
894 | 1 | break; | |
895 | } | ||
896 | 1 | } | |
897 | |||
898 | static void | ||
899 | 1 | elanmoc_delete_print (FpDevice *device) | |
900 | { | ||
901 | 1 | g_autoptr(GVariant) data = NULL; | |
902 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | g_autoptr(GVariant) user_id_var = NULL; |
903 | 1 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (device); | |
904 | 1 | FpPrint *print = NULL; | |
905 | 1 | const guint8 *user_id; | |
906 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | g_autofree char *user_id_safe = NULL; |
907 | 1 | gsize user_id_len = 0; | |
908 | 1 | guint8 *userid_buf = NULL; | |
909 | |||
910 | 1 | fpi_device_get_delete_data (device, &print); | |
911 | 1 | g_object_get (print, "fpi-data", &data, NULL); | |
912 | |||
913 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!g_variant_check_format_string (data, "(yy@ay)", FALSE)) |
914 | { | ||
915 | ✗ | fpi_device_delete_complete (device, | |
916 | fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); | ||
917 | ✗ | return; | |
918 | } | ||
919 | |||
920 | 1 | userid_buf = g_malloc0 (ELAN_USERDATE_SIZE); | |
921 | |||
922 | 1 | g_variant_get (data, | |
923 | "(yy@ay)", | ||
924 | &userid_buf[0], | ||
925 | &userid_buf[1], | ||
926 | &user_id_var); | ||
927 | 1 | user_id = g_variant_get_fixed_array (user_id_var, &user_id_len, 1); | |
928 | 1 | user_id_safe = g_strndup ((const char *) user_id, user_id_len); | |
929 | 1 | user_id_len = MIN (ELAN_MAX_USER_ID_LEN, user_id_len); | |
930 | 1 | userid_buf[2] = user_id_len; | |
931 | 1 | memcpy (userid_buf + 3, user_id, user_id_len); | |
932 | |||
933 | 1 | fp_info ("Delete Finger, user_id = %s!", user_id_safe); | |
934 | 1 | self->task_ssm = fpi_ssm_new (device, | |
935 | elan_delete_run_state, | ||
936 | DELETE_NUM_STATES); | ||
937 | 1 | fpi_ssm_set_data (self->task_ssm, userid_buf, g_free); | |
938 | 1 | fpi_ssm_start (self->task_ssm, task_ssm_done); | |
939 | } | ||
940 | |||
941 | static void | ||
942 | 2 | elanmoc_identify (FpDevice *device) | |
943 | { | ||
944 | 2 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (device); | |
945 | |||
946 | 2 | self->task_ssm = fpi_ssm_new (device, | |
947 | elan_identify_run_state, | ||
948 | IDENTIFY_NUM_STATES); | ||
949 | 2 | fpi_ssm_start (self->task_ssm, task_ssm_done); | |
950 | 2 | } | |
951 | |||
952 | static void | ||
953 | 1 | task_ssm_init_done (FpiSsm *ssm, FpDevice *dev, GError *error) | |
954 | { | ||
955 | 1 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (dev); | |
956 | |||
957 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
958 | ✗ | g_usb_device_release_interface (fpi_device_get_usb_device (dev), | |
959 | 0, 0, NULL); | ||
960 | |||
961 | 1 | fpi_device_open_complete (FP_DEVICE (self), error); | |
962 | 1 | } | |
963 | |||
964 | static void | ||
965 | 1 | elanmoc_cmd_ver_cb (FpiDeviceElanmoc *self, | |
966 | uint8_t *buffer_in, | ||
967 | gsize length_in, | ||
968 | GError *error) | ||
969 | { | ||
970 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
971 | { | ||
972 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
973 | ✗ | return; | |
974 | } | ||
975 | |||
976 | 1 | self->fw_ver = (buffer_in[0] << 8 | buffer_in[1]); | |
977 | 1 | fp_info ("elanmoc FW Version %x ", self->fw_ver); | |
978 | 1 | fpi_ssm_next_state (self->task_ssm); | |
979 | } | ||
980 | |||
981 | static void | ||
982 | 1 | elanmoc_cmd_dim_cb (FpiDeviceElanmoc *self, | |
983 | uint8_t *buffer_in, | ||
984 | gsize length_in, | ||
985 | GError *error) | ||
986 | { | ||
987 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
988 | { | ||
989 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
990 | ✗ | return; | |
991 | } | ||
992 | |||
993 | 1 | self->x_trace = buffer_in[0]; | |
994 | 1 | self->y_trace = buffer_in[2]; | |
995 | 1 | fp_info ("elanmoc last_read DIM 0x%.2X(%d) 0x%.2X(%d)", self->x_trace, self->x_trace, | |
996 | self->y_trace, self->y_trace); | ||
997 | 1 | fpi_ssm_next_state (self->task_ssm); | |
998 | } | ||
999 | |||
1000 | static void | ||
1001 | 1 | elanmoc_get_status_cb (FpiDeviceElanmoc *self, | |
1002 | uint8_t *buffer_in, | ||
1003 | gsize length_in, | ||
1004 | GError *error) | ||
1005 | { | ||
1006 | 1 | guint8 *cmd_buf = NULL; | |
1007 | |||
1008 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
1009 | { | ||
1010 | ✗ | fpi_ssm_mark_failed (self->task_ssm, error); | |
1011 | ✗ | return; | |
1012 | } | ||
1013 | |||
1014 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | if (buffer_in[1] != 0x03 && self->cmd_retry_cnt != 0) |
1015 | { | ||
1016 | ✗ | self->cmd_retry_cnt--; | |
1017 | ✗ | cmd_buf = elanmoc_compose_cmd (&cal_status_cmd); | |
1018 | ✗ | elanmoc_get_cmd (FP_DEVICE (self), cmd_buf, cal_status_cmd.cmd_len, cal_status_cmd.resp_len, 0, elanmoc_get_status_cb); | |
1019 | } | ||
1020 | else | ||
1021 | { | ||
1022 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if(self->cmd_retry_cnt == 0) |
1023 | { | ||
1024 | ✗ | fpi_ssm_mark_failed (self->task_ssm, | |
1025 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
1026 | "Sensor not ready")); | ||
1027 | ✗ | return; | |
1028 | } | ||
1029 | 1 | fpi_ssm_next_state (self->task_ssm); | |
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | static void | ||
1034 | 5 | dev_init_handler (FpiSsm *ssm, FpDevice *dev) | |
1035 | { | ||
1036 | 5 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (dev); | |
1037 | 5 | guint8 *cmd_buf = NULL; | |
1038 | |||
1039 |
5/6✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
5 | switch (fpi_ssm_get_cur_state (ssm)) |
1040 | { | ||
1041 | 1 | case DEV_WAIT_READY: | |
1042 | 1 | self->cmd_retry_cnt = ELAN_MOC_CAL_RETRY; | |
1043 | 1 | cmd_buf = elanmoc_compose_cmd (&cal_status_cmd); | |
1044 | 1 | elanmoc_get_cmd (dev, cmd_buf, cal_status_cmd.cmd_len, cal_status_cmd.resp_len, 0, elanmoc_get_status_cb); | |
1045 | 1 | break; | |
1046 | |||
1047 | 1 | case DEV_SET_MODE: | |
1048 | 1 | cmd_buf = elanmoc_compose_cmd (&elanmoc_set_mod_cmd); | |
1049 | 1 | cmd_buf[3] = 0x03; | |
1050 | 1 | elanmoc_get_cmd (dev, cmd_buf, elanmoc_set_mod_cmd.cmd_len, elanmoc_set_mod_cmd.resp_len, 0, elanmoc_cmd_ack_cb); | |
1051 | 1 | break; | |
1052 | |||
1053 | 1 | case DEV_GET_VER: | |
1054 | 1 | cmd_buf = elanmoc_compose_cmd (&fw_ver_cmd); | |
1055 | 1 | elanmoc_get_cmd (dev, cmd_buf, fw_ver_cmd.cmd_len, fw_ver_cmd.resp_len, 0, elanmoc_cmd_ver_cb); | |
1056 | 1 | break; | |
1057 | |||
1058 | 1 | case DEV_GET_DIM: | |
1059 | 1 | cmd_buf = elanmoc_compose_cmd (&sensor_dim_cmd); | |
1060 | 1 | elanmoc_get_cmd (dev, cmd_buf, sensor_dim_cmd.cmd_len, sensor_dim_cmd.resp_len, 0, elanmoc_cmd_dim_cb); | |
1061 | 1 | break; | |
1062 | |||
1063 | 1 | case DEV_GET_ENROLLED: | |
1064 | 1 | cmd_buf = elanmoc_compose_cmd (&enrolled_number_cmd); | |
1065 | 1 | elanmoc_get_cmd (dev, cmd_buf, enrolled_number_cmd.cmd_len, enrolled_number_cmd.resp_len, 0, elanmoc_get_enrolled_cb); | |
1066 | 1 | break; | |
1067 | |||
1068 | } | ||
1069 | 5 | } | |
1070 | |||
1071 | static void | ||
1072 | 1 | elanmoc_open (FpDevice *device) | |
1073 | { | ||
1074 | 1 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (device); | |
1075 | 1 | GError *error = NULL; | |
1076 | 1 | gint productid = 0; | |
1077 | |||
1078 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error)) |
1079 | ✗ | goto error; | |
1080 | |||
1081 |
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)) |
1082 | ✗ | goto error; | |
1083 | |||
1084 | 1 | productid = g_usb_device_get_pid (fpi_device_get_usb_device (device)); | |
1085 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | switch (productid) |
1086 | { | ||
1087 | ✗ | case 0x0c8c: | |
1088 | ✗ | self->max_moc_enroll_time = 11; | |
1089 | ✗ | break; | |
1090 | |||
1091 | ✗ | case 0x0c99: | |
1092 | ✗ | self->max_moc_enroll_time = 14; | |
1093 | ✗ | break; | |
1094 | |||
1095 | ✗ | case 0x0c8d: | |
1096 | ✗ | self->max_moc_enroll_time = 17; | |
1097 | ✗ | break; | |
1098 | |||
1099 | 1 | default: | |
1100 | 1 | self->max_moc_enroll_time = ELAN_MOC_ENROLL_TIMES; | |
1101 | 1 | break; | |
1102 | } | ||
1103 | |||
1104 | 1 | fpi_device_set_nr_enroll_stages (device, self->max_moc_enroll_time); | |
1105 | |||
1106 | 1 | self->task_ssm = fpi_ssm_new (FP_DEVICE (self), dev_init_handler, DEV_INIT_STATES); | |
1107 | 1 | fpi_ssm_start (self->task_ssm, task_ssm_init_done); | |
1108 | 1 | return; | |
1109 | |||
1110 | ✗ | error: | |
1111 | ✗ | fpi_device_open_complete (FP_DEVICE (self), error); | |
1112 | } | ||
1113 | |||
1114 | static void | ||
1115 | 1 | task_ssm_exit_done (FpiSsm *ssm, FpDevice *dev, GError *error) | |
1116 | { | ||
1117 | 1 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (dev); | |
1118 | |||
1119 | 1 | g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)), 0, 0, &error); | |
1120 | 1 | fpi_device_close_complete (FP_DEVICE (self), error); | |
1121 | 1 | self->task_ssm = NULL; | |
1122 | 1 | } | |
1123 | |||
1124 | static void | ||
1125 | 1 | dev_exit_handler (FpiSsm *ssm, FpDevice *dev) | |
1126 | { | ||
1127 | 1 | guint8 *cmd_buf = NULL; | |
1128 | |||
1129 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | switch (fpi_ssm_get_cur_state (ssm)) |
1130 | { | ||
1131 | 1 | case DEV_EXIT_ABOVE: | |
1132 | 1 | cmd_buf = elanmoc_compose_cmd (&elanmoc_above_cmd); | |
1133 | 1 | elanmoc_get_cmd (dev, cmd_buf, elanmoc_above_cmd.cmd_len, elanmoc_above_cmd.resp_len, 0, elanmoc_cmd_ack_cb); | |
1134 | 1 | break; | |
1135 | } | ||
1136 | 1 | } | |
1137 | |||
1138 | static void | ||
1139 | 1 | elanmoc_close (FpDevice *device) | |
1140 | { | ||
1141 | 1 | FpiDeviceElanmoc *self = FPI_DEVICE_ELANMOC (device); | |
1142 | |||
1143 | 1 | fp_info ("Elanmoc dev_exit"); | |
1144 | 1 | self->task_ssm = fpi_ssm_new (FP_DEVICE (self), dev_exit_handler, DEV_EXIT_STATES); | |
1145 | 1 | fpi_ssm_start (self->task_ssm, task_ssm_exit_done); | |
1146 | 1 | } | |
1147 | |||
1148 | static void | ||
1149 | 1 | fpi_device_elanmoc_init (FpiDeviceElanmoc *self) | |
1150 | { | ||
1151 | 1 | G_DEBUG_HERE (); | |
1152 | 1 | } | |
1153 | |||
1154 | static void | ||
1155 | 120 | fpi_device_elanmoc_class_init (FpiDeviceElanmocClass *klass) | |
1156 | { | ||
1157 | 120 | FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); | |
1158 | |||
1159 | 120 | dev_class->id = FP_COMPONENT; | |
1160 | 120 | dev_class->full_name = ELAN_MOC_DRIVER_FULLNAME; | |
1161 | |||
1162 | 120 | dev_class->type = FP_DEVICE_TYPE_USB; | |
1163 | 120 | dev_class->scan_type = FP_SCAN_TYPE_PRESS; | |
1164 | 120 | dev_class->id_table = id_table; | |
1165 | 120 | dev_class->nr_enroll_stages = ELAN_MOC_ENROLL_TIMES; | |
1166 | 120 | dev_class->temp_hot_seconds = -1; | |
1167 | |||
1168 | 120 | dev_class->open = elanmoc_open; | |
1169 | 120 | dev_class->close = elanmoc_close; | |
1170 | 120 | dev_class->verify = elanmoc_identify; | |
1171 | 120 | dev_class->enroll = elanmoc_enroll; | |
1172 | 120 | dev_class->identify = elanmoc_identify; | |
1173 | 120 | dev_class->delete = elanmoc_delete_print; | |
1174 | 120 | dev_class->list = elanmoc_list; | |
1175 | |||
1176 | 120 | fpi_device_class_auto_initialize_features (dev_class); | |
1177 | 120 | } | |
1178 |