Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * UPEK TouchChip driver for libfprint | ||
3 | * Copyright (C) 2013 Vasily Khoruzhick <anarsoul@gmail.com> | ||
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 | #define FP_COMPONENT "upektc_img" | ||
21 | |||
22 | #include "drivers_api.h" | ||
23 | #include "upek_proto.h" | ||
24 | #include "upektc_img.h" | ||
25 | |||
26 | static void start_capture (FpImageDevice *dev); | ||
27 | static void start_deactivation (FpImageDevice *dev); | ||
28 | |||
29 | #define EP_IN (1 | FPI_USB_ENDPOINT_IN) | ||
30 | #define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) | ||
31 | #define CTRL_TIMEOUT 4000 | ||
32 | #define BULK_TIMEOUT 4000 | ||
33 | |||
34 | #define MAX_CMD_SIZE 64 | ||
35 | #define MAX_RESPONSE_SIZE 2052 | ||
36 | #define SHORT_RESPONSE_SIZE 64 | ||
37 | |||
38 | struct _FpiDeviceUpektcImg | ||
39 | { | ||
40 | FpImageDevice parent; | ||
41 | |||
42 | unsigned char cmd[MAX_CMD_SIZE]; | ||
43 | unsigned char response[MAX_RESPONSE_SIZE]; | ||
44 | unsigned char *image_bits; | ||
45 | unsigned char seq; | ||
46 | size_t expected_image_size; | ||
47 | size_t image_size; | ||
48 | size_t response_rest; | ||
49 | gboolean area_sensor; | ||
50 | gboolean deactivating; | ||
51 | }; | ||
52 | G_DECLARE_FINAL_TYPE (FpiDeviceUpektcImg, fpi_device_upektc_img, FPI, | ||
53 | DEVICE_UPEKTC_IMG, FpImageDevice); | ||
54 |
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 (FpiDeviceUpektcImg, fpi_device_upektc_img, FP_TYPE_IMAGE_DEVICE); |
55 | |||
56 | /****** HELPERS ******/ | ||
57 | |||
58 | static void | ||
59 | 70 | upektc_img_cmd_fix_seq (unsigned char *cmd_buf, unsigned char seq) | |
60 | { | ||
61 | 70 | uint8_t byte; | |
62 | |||
63 | 70 | byte = cmd_buf[5]; | |
64 | 70 | byte &= 0x0f; | |
65 | 70 | byte |= (seq << 4); | |
66 | 70 | cmd_buf[5] = byte; | |
67 | } | ||
68 | |||
69 | static void | ||
70 | 70 | upektc_img_cmd_update_crc (unsigned char *cmd_buf, size_t size) | |
71 | { | ||
72 | /* CRC does not cover Ciao prefix (4 bytes) and CRC location (2 bytes) */ | ||
73 | 70 | uint16_t crc = udf_crc (cmd_buf + 4, size - 6); | |
74 | |||
75 | 70 | cmd_buf[size - 2] = (crc & 0x00ff); | |
76 | 70 | cmd_buf[size - 1] = (crc & 0xff00) >> 8; | |
77 | 70 | } | |
78 | |||
79 | FP_GNUC_ACCESS (read_only, 3, 4) | ||
80 | static void | ||
81 | 70 | upektc_img_submit_req (FpiSsm *ssm, | |
82 | FpImageDevice *dev, | ||
83 | const unsigned char *buf, | ||
84 | size_t buf_size, | ||
85 | unsigned char seq, | ||
86 | FpiUsbTransferCallback cb) | ||
87 | { | ||
88 | 70 | FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); | |
89 | 70 | FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); | |
90 | |||
91 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
|
70 | BUG_ON (buf_size > MAX_CMD_SIZE); |
92 | |||
93 | 70 | memcpy (self->cmd, buf, buf_size); | |
94 | 70 | upektc_img_cmd_fix_seq (self->cmd, seq); | |
95 | 70 | upektc_img_cmd_update_crc (self->cmd, buf_size); | |
96 | |||
97 | 70 | fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, self->cmd, buf_size, | |
98 | NULL); | ||
99 | 70 | transfer->ssm = ssm; | |
100 | 70 | transfer->short_is_error = TRUE; | |
101 | 70 | fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, cb, NULL); | |
102 | 70 | } | |
103 | |||
104 | static void | ||
105 | 132 | upektc_img_read_data (FpiSsm *ssm, | |
106 | FpImageDevice *dev, | ||
107 | size_t buf_size, | ||
108 | size_t buf_offset, | ||
109 | FpiUsbTransferCallback cb) | ||
110 | { | ||
111 | 132 | FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); | |
112 | 132 | FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); | |
113 | |||
114 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
|
132 | BUG_ON (buf_offset + buf_size > MAX_RESPONSE_SIZE); |
115 | |||
116 | 132 | fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, | |
117 | 132 | self->response + buf_offset, buf_size, | |
118 | NULL); | ||
119 | 132 | transfer->ssm = ssm; | |
120 | 132 | fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, cb, NULL); | |
121 | 132 | } | |
122 | |||
123 | /****** CAPTURE ******/ | ||
124 | |||
125 | enum capture_states { | ||
126 | CAPTURE_INIT_CAPTURE, | ||
127 | CAPTURE_READ_DATA, | ||
128 | CAPTURE_READ_DATA_TERM, | ||
129 | CAPTURE_ACK_00_28, | ||
130 | CAPTURE_ACK_08, | ||
131 | CAPTURE_ACK_FRAME, | ||
132 | CAPTURE_ACK_00_28_TERM, | ||
133 | CAPTURE_NUM_STATES, | ||
134 | }; | ||
135 | |||
136 | static void | ||
137 | 60 | capture_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device, | |
138 | gpointer user_data, GError *error) | ||
139 | { | ||
140 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | if (error) |
141 | { | ||
142 | ✗ | fpi_ssm_mark_failed (transfer->ssm, error); | |
143 | ✗ | return; | |
144 | } | ||
145 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
|
60 | switch (fpi_ssm_get_cur_state (transfer->ssm)) |
146 | { | ||
147 | ✗ | case CAPTURE_ACK_00_28_TERM: | |
148 | ✗ | fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA_TERM); | |
149 | ✗ | break; | |
150 | |||
151 | 60 | default: | |
152 | 60 | fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA); | |
153 | 60 | break; | |
154 | } | ||
155 | } | ||
156 | |||
157 | static int | ||
158 | 54 | upektc_img_process_image_frame (unsigned char *image_buf, unsigned char *cmd_res) | |
159 | { | ||
160 | 54 | int offset = 8; | |
161 | 54 | int len = ((cmd_res[5] & 0x0f) << 8) | (cmd_res[6]); | |
162 | |||
163 | 54 | len -= 1; | |
164 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 52 times.
|
54 | if (cmd_res[7] == 0x2c) |
165 | { | ||
166 | 2 | len -= 10; | |
167 | 2 | offset += 10; | |
168 | } | ||
169 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 52 times.
|
54 | if (cmd_res[7] == 0x20) |
170 | 2 | len -= 4; | |
171 | 54 | memcpy (image_buf, cmd_res + offset, len); | |
172 | |||
173 | 54 | return len; | |
174 | } | ||
175 | |||
176 | static void | ||
177 | 118 | capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, | |
178 | gpointer user_data, GError *error) | ||
179 | { | ||
180 | 118 | FpImageDevice *dev = FP_IMAGE_DEVICE (device); | |
181 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
|
118 | FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_GET_CLASS (dev); |
182 | 118 | FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); | |
183 | 118 | unsigned char *data = self->response; | |
184 | 118 | FpImage *img; | |
185 | 118 | size_t response_size; | |
186 | |||
187 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
|
118 | if (error) |
188 | { | ||
189 | ✗ | fp_dbg ("request is not completed, %s", error->message); | |
190 | ✗ | fpi_ssm_mark_failed (transfer->ssm, error); | |
191 | ✗ | return; | |
192 | } | ||
193 | |||
194 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
|
118 | if (self->deactivating) |
195 | { | ||
196 | ✗ | fp_dbg ("Deactivate requested"); | |
197 | ✗ | fpi_ssm_mark_completed (transfer->ssm); | |
198 | ✗ | return; | |
199 | } | ||
200 | |||
201 | 118 | fp_dbg ("request completed, len: %.4x", (gint) transfer->actual_length); | |
202 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 114 times.
|
118 | if (transfer->actual_length == 0) |
203 | { | ||
204 | 4 | fpi_ssm_jump_to_state (transfer->ssm, | |
205 | fpi_ssm_get_cur_state (transfer->ssm)); | ||
206 | 4 | return; | |
207 | } | ||
208 | |||
209 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 114 times.
|
114 | if (fpi_ssm_get_cur_state (transfer->ssm) == CAPTURE_READ_DATA_TERM) |
210 | { | ||
211 | ✗ | fp_dbg ("Terminating SSM"); | |
212 | ✗ | fpi_ssm_mark_completed (transfer->ssm); | |
213 | ✗ | return; | |
214 | } | ||
215 | |||
216 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 54 times.
|
114 | if (!self->response_rest) |
217 | { | ||
218 | 60 | response_size = ((data[5] & 0x0f) << 8) + data[6]; | |
219 | 60 | response_size += 9; /* 7 bytes for header, 2 for CRC */ | |
220 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 6 times.
|
60 | if (response_size > transfer->actual_length) |
221 | { | ||
222 | 54 | fp_dbg ("response_size is %lu, actual_length is %d", | |
223 | (gulong) response_size, (gint) transfer->actual_length); | ||
224 | 54 | fp_dbg ("Waiting for rest of transfer"); | |
225 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
|
54 | BUG_ON (self->response_rest); |
226 | 54 | self->response_rest = response_size - transfer->actual_length; | |
227 | 54 | fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA); | |
228 | 54 | return; | |
229 | } | ||
230 | } | ||
231 | 60 | self->response_rest = 0; | |
232 | |||
233 |
2/3✓ Branch 0 taken 59 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
60 | switch (data[4]) |
234 | { | ||
235 | 59 | case 0x00: | |
236 |
4/5✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
59 | switch (data[7]) |
237 | { | ||
238 | /* No finger */ | ||
239 | 5 | case 0x28: | |
240 | 5 | fp_dbg ("18th byte is %.2x", data[18]); | |
241 |
3/7✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
5 | switch (data[18]) |
242 | { | ||
243 | 2 | case 0x0c: | |
244 | /* no finger */ | ||
245 | 2 | fpi_ssm_jump_to_state (transfer->ssm, | |
246 | CAPTURE_ACK_00_28); | ||
247 | 2 | break; | |
248 | |||
249 | 1 | case 0x13: | |
250 | /* finger is present keep your finger on reader */ | ||
251 | 1 | fpi_device_report_finger_status_changes (device, | |
252 | FP_FINGER_STATUS_NEEDED, | ||
253 | FP_FINGER_STATUS_NONE); | ||
254 | 2 | fpi_ssm_jump_to_state (transfer->ssm, | |
255 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | self->area_sensor ? |
256 | CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM); | ||
257 | 1 | break; | |
258 | |||
259 | 2 | case 0x00: | |
260 | /* finger is present! */ | ||
261 | 2 | fpi_device_report_finger_status_changes (device, | |
262 | FP_FINGER_STATUS_PRESENT, | ||
263 | FP_FINGER_STATUS_NONE); | ||
264 | 2 | fpi_ssm_jump_to_state (transfer->ssm, | |
265 | CAPTURE_ACK_00_28); | ||
266 | 2 | break; | |
267 | |||
268 | ✗ | case 0x01: | |
269 | /* no finger! */ | ||
270 | ✗ | fpi_device_report_finger_status_changes (device, | |
271 | FP_FINGER_STATUS_NONE, | ||
272 | FP_FINGER_STATUS_PRESENT); | ||
273 | ✗ | fpi_ssm_jump_to_state (transfer->ssm, | |
274 | CAPTURE_ACK_00_28); | ||
275 | ✗ | break; | |
276 | |||
277 | ✗ | case 0x1e: | |
278 | /* short scan */ | ||
279 | ✗ | fp_err ("short scan, aborting"); | |
280 | ✗ | fpi_image_device_retry_scan (dev, | |
281 | FP_DEVICE_RETRY_TOO_SHORT); | ||
282 | ✗ | fpi_image_device_report_finger_status (dev, | |
283 | FALSE); | ||
284 | ✗ | fpi_ssm_jump_to_state (transfer->ssm, | |
285 | ✗ | self->area_sensor ? | |
286 | CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM); | ||
287 | ✗ | break; | |
288 | |||
289 | ✗ | case 0x1d: | |
290 | /* too much horizontal movement */ | ||
291 | ✗ | fp_err ("too much horizontal movement, aborting"); | |
292 | ✗ | fpi_image_device_retry_scan (dev, | |
293 | FP_DEVICE_RETRY_CENTER_FINGER); | ||
294 | ✗ | fpi_image_device_report_finger_status (dev, | |
295 | FALSE); | ||
296 | ✗ | fpi_ssm_jump_to_state (transfer->ssm, | |
297 | ✗ | self->area_sensor ? | |
298 | CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM); | ||
299 | ✗ | break; | |
300 | |||
301 | ✗ | default: | |
302 | /* some error happened, cancel scan */ | ||
303 | ✗ | fp_err ("something bad happened, stop scan"); | |
304 | ✗ | fpi_image_device_retry_scan (dev, | |
305 | ✗ | FP_DEVICE_RETRY); | |
306 | ✗ | fpi_image_device_report_finger_status (dev, | |
307 | FALSE); | ||
308 | ✗ | fpi_ssm_jump_to_state (transfer->ssm, | |
309 | ✗ | self->area_sensor ? | |
310 | CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM); | ||
311 | ✗ | break; | |
312 | } | ||
313 | break; | ||
314 | |||
315 | /* Image frame with additional info */ | ||
316 | 2 | case 0x2c: | |
317 | 2 | fpi_image_device_report_finger_status (dev, | |
318 | TRUE); | ||
319 | |||
320 | /* Plain image frame */ | ||
321 | 52 | case 0x24: | |
322 | 104 | self->image_size += | |
323 | 52 | upektc_img_process_image_frame (self->image_bits + self->image_size, | |
324 | data); | ||
325 | 52 | fpi_ssm_jump_to_state (transfer->ssm, | |
326 | CAPTURE_ACK_FRAME); | ||
327 | 52 | break; | |
328 | |||
329 | /* Last image frame */ | ||
330 | 2 | case 0x20: | |
331 | 4 | self->image_size += | |
332 | 2 | upektc_img_process_image_frame (self->image_bits + self->image_size, | |
333 | data); | ||
334 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | BUG_ON (self->image_size != self->expected_image_size); |
335 | 2 | fp_dbg ("Image size is %lu", | |
336 | (gulong) self->image_size); | ||
337 | 2 | img = fp_image_new (img_class->img_width, img_class->img_height); | |
338 | 2 | img->flags |= FPI_IMAGE_PARTIAL; | |
339 | 2 | memcpy (img->data, self->image_bits, | |
340 | self->image_size); | ||
341 | 2 | fpi_image_device_image_captured (dev, img); | |
342 | 2 | fpi_image_device_report_finger_status (dev, | |
343 | FALSE); | ||
344 | 2 | fpi_ssm_mark_completed (transfer->ssm); | |
345 | 2 | break; | |
346 | |||
347 | ✗ | default: | |
348 | ✗ | fp_err ("Unknown response!"); | |
349 | ✗ | fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); | |
350 | ✗ | break; | |
351 | } | ||
352 | break; | ||
353 | |||
354 | 1 | case 0x08: | |
355 | 1 | fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_ACK_08); | |
356 | 1 | break; | |
357 | |||
358 | ✗ | default: | |
359 | ✗ | fp_err ("Not handled response!"); | |
360 | ✗ | fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); | |
361 | } | ||
362 | } | ||
363 | |||
364 | static void | ||
365 | 178 | capture_run_state (FpiSsm *ssm, FpDevice *_dev) | |
366 | { | ||
367 | 178 | FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); | |
368 | 178 | FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev); | |
369 | |||
370 |
5/6✓ Branch 1 taken 2 times.
✓ Branch 2 taken 118 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 52 times.
✗ Branch 6 not taken.
|
178 | switch (fpi_ssm_get_cur_state (ssm)) |
371 | { | ||
372 | 2 | case CAPTURE_INIT_CAPTURE: | |
373 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (self->area_sensor) |
374 | 1 | upektc_img_submit_req (ssm, dev, upek2020_init_capture_press, sizeof (upek2020_init_capture_press), | |
375 | 1 | self->seq, capture_reqs_cb); | |
376 | else | ||
377 | 1 | upektc_img_submit_req (ssm, dev, upek2020_init_capture, sizeof (upek2020_init_capture), | |
378 | 1 | self->seq, capture_reqs_cb); | |
379 | 2 | self->seq++; | |
380 | 2 | break; | |
381 | |||
382 | 118 | case CAPTURE_READ_DATA: | |
383 | case CAPTURE_READ_DATA_TERM: | ||
384 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 54 times.
|
118 | if (!self->response_rest) |
385 | 64 | upektc_img_read_data (ssm, dev, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb); | |
386 | else | ||
387 | 54 | upektc_img_read_data (ssm, dev, MAX_RESPONSE_SIZE - SHORT_RESPONSE_SIZE, | |
388 | SHORT_RESPONSE_SIZE, capture_read_data_cb); | ||
389 | break; | ||
390 | |||
391 | 5 | case CAPTURE_ACK_00_28: | |
392 | case CAPTURE_ACK_00_28_TERM: | ||
393 | 5 | upektc_img_submit_req (ssm, dev, upek2020_ack_00_28, sizeof (upek2020_ack_00_28), | |
394 | 5 | self->seq, capture_reqs_cb); | |
395 | 5 | self->seq++; | |
396 | 5 | break; | |
397 | |||
398 | 1 | case CAPTURE_ACK_08: | |
399 | 1 | upektc_img_submit_req (ssm, dev, upek2020_ack_08, sizeof (upek2020_ack_08), | |
400 | 0, capture_reqs_cb); | ||
401 | 1 | break; | |
402 | |||
403 | 52 | case CAPTURE_ACK_FRAME: | |
404 | 52 | upektc_img_submit_req (ssm, dev, upek2020_ack_frame, sizeof (upek2020_ack_frame), | |
405 | 52 | self->seq, capture_reqs_cb); | |
406 | 52 | self->seq++; | |
407 | 52 | break; | |
408 | } | ||
409 | 178 | ; | |
410 | 178 | } | |
411 | |||
412 | static void | ||
413 | 2 | capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error_arg) | |
414 | { | ||
415 | 2 | FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); | |
416 | 2 | FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev); | |
417 | |||
418 | 4 | g_autoptr(GError) error = error_arg; | |
419 | |||
420 | |||
421 | /* Note: We assume that the error is a cancellation in the deactivation case */ | ||
422 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (self->deactivating) |
423 | 2 | start_deactivation (dev); | |
424 | ✗ | else if (error) | |
425 | ✗ | fpi_image_device_session_error (dev, g_steal_pointer (&error)); | |
426 | else | ||
427 | ✗ | start_capture (dev); | |
428 | 2 | } | |
429 | |||
430 | static void | ||
431 | 2 | start_capture (FpImageDevice *dev) | |
432 | { | ||
433 | 2 | FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); | |
434 | 2 | FpiSsm *ssm; | |
435 | |||
436 | 2 | self->image_size = 0; | |
437 | |||
438 | 2 | ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, | |
439 | CAPTURE_NUM_STATES); | ||
440 | 2 | fpi_ssm_start (ssm, capture_sm_complete); | |
441 | 2 | } | |
442 | |||
443 | /****** INITIALIZATION/DEINITIALIZATION ******/ | ||
444 | |||
445 | enum deactivate_states { | ||
446 | DEACTIVATE_DEINIT, | ||
447 | DEACTIVATE_READ_DEINIT_DATA, | ||
448 | DEACTIVATE_NUM_STATES, | ||
449 | }; | ||
450 | |||
451 | static void | ||
452 | 2 | deactivate_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device, | |
453 | gpointer user_data, GError *error) | ||
454 | { | ||
455 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!error) |
456 | 2 | fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA); | |
457 | else | ||
458 | ✗ | fpi_ssm_mark_failed (transfer->ssm, error); | |
459 | 2 | } | |
460 | |||
461 | /* TODO: process response properly */ | ||
462 | static void | ||
463 | 2 | deactivate_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, | |
464 | gpointer user_data, GError *error) | ||
465 | { | ||
466 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!error) |
467 | 2 | fpi_ssm_mark_completed (transfer->ssm); | |
468 | else | ||
469 | ✗ | fpi_ssm_mark_failed (transfer->ssm, error); | |
470 | 2 | } | |
471 | |||
472 | static void | ||
473 | 4 | deactivate_run_state (FpiSsm *ssm, FpDevice *_dev) | |
474 | { | ||
475 | 4 | FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); | |
476 | 4 | FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev); | |
477 | |||
478 |
2/3✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
4 | switch (fpi_ssm_get_cur_state (ssm)) |
479 | { | ||
480 | 2 | case DEACTIVATE_DEINIT: | |
481 | 2 | upektc_img_submit_req (ssm, dev, upek2020_deinit, sizeof (upek2020_deinit), | |
482 | 2 | self->seq, deactivate_reqs_cb); | |
483 | 2 | self->seq++; | |
484 | 2 | break; | |
485 | |||
486 | 2 | case DEACTIVATE_READ_DEINIT_DATA: | |
487 | 2 | upektc_img_read_data (ssm, dev, SHORT_RESPONSE_SIZE, 0, deactivate_read_data_cb); | |
488 | 2 | break; | |
489 | } | ||
490 | 4 | ; | |
491 | 4 | } | |
492 | |||
493 | static void | ||
494 | 2 | deactivate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) | |
495 | { | ||
496 | 2 | FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); | |
497 | 2 | FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev); | |
498 | |||
499 | 2 | fp_dbg ("Deactivate completed"); | |
500 | |||
501 | 2 | self->deactivating = FALSE; | |
502 | 2 | fpi_image_device_deactivate_complete (dev, error); | |
503 | 2 | } | |
504 | |||
505 | static void | ||
506 | 2 | start_deactivation (FpImageDevice *dev) | |
507 | { | ||
508 | 2 | FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); | |
509 | 2 | FpiSsm *ssm; | |
510 | |||
511 | 2 | self->image_size = 0; | |
512 | |||
513 | 2 | ssm = fpi_ssm_new (FP_DEVICE (dev), deactivate_run_state, | |
514 | DEACTIVATE_NUM_STATES); | ||
515 | 2 | fpi_ssm_start (ssm, deactivate_sm_complete); | |
516 | 2 | } | |
517 | |||
518 | enum activate_states { | ||
519 | ACTIVATE_CONTROL_REQ_1, | ||
520 | ACTIVATE_READ_CTRL_RESP_1, | ||
521 | ACTIVATE_INIT_1, | ||
522 | ACTIVATE_READ_INIT_1_RESP, | ||
523 | ACTIVATE_INIT_2, | ||
524 | ACTIVATE_READ_INIT_2_RESP, | ||
525 | ACTIVATE_CONTROL_REQ_2, | ||
526 | ACTIVATE_READ_CTRL_RESP_2, | ||
527 | ACTIVATE_INIT_3, | ||
528 | ACTIVATE_READ_INIT_3_RESP, | ||
529 | ACTIVATE_INIT_4, | ||
530 | ACTIVATE_READ_INIT_4_RESP, | ||
531 | ACTIVATE_NUM_STATES, | ||
532 | }; | ||
533 | |||
534 | static void | ||
535 | 8 | init_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device, | |
536 | gpointer user_data, GError *error) | ||
537 | { | ||
538 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (!error) |
539 | 8 | fpi_ssm_next_state (transfer->ssm); | |
540 | else | ||
541 | ✗ | fpi_ssm_mark_failed (transfer->ssm, error); | |
542 | 8 | } | |
543 | |||
544 | static void | ||
545 | 12 | init_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, | |
546 | gpointer user_data, GError *error) | ||
547 | { | ||
548 | 12 | FpImageDevice *dev = FP_IMAGE_DEVICE (device); | |
549 | 12 | FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); | |
550 | 12 | unsigned char *data = self->response; | |
551 | |||
552 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (error) |
553 | { | ||
554 | ✗ | fpi_ssm_mark_failed (transfer->ssm, error); | |
555 | ✗ | return; | |
556 | } | ||
557 | |||
558 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
12 | if (data[12] == 0x06 && data[13] == 0x14) /* if get_info */ |
559 | { | ||
560 |
2/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
2 | FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_GET_CLASS (dev); |
561 | 2 | uint16_t width = (data[51] << 8) | data[50]; | |
562 | 2 | uint16_t height = (data[53] << 8) | data[52]; | |
563 | |||
564 | 2 | self->area_sensor = !(data[49] & 0x80); | |
565 | |||
566 |
2/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
2 | switch (width) |
567 | { | ||
568 | 1 | case 256: | |
569 | 1 | fp_dbg ("Sensor type : TCS1x, width x height: %hu x %hu", width, height); /* 360x256 --- 270x192 must be set */ | |
570 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | BUG_ON (height != 360); |
571 | 1 | img_class->img_width = 192; | |
572 | 1 | img_class->img_height = 270; | |
573 | 1 | break; | |
574 | |||
575 | ✗ | case 208: | |
576 | ✗ | fp_dbg ("Sensor type : TCS2, width x height: %hu x %hu", width, height); /* 288x208 --- 216x156 must be set */ | |
577 | ✗ | BUG_ON (height != 288); | |
578 | ✗ | img_class->img_width = 156; | |
579 | ✗ | img_class->img_height = 216; | |
580 | ✗ | break; | |
581 | |||
582 | ✗ | case 248: | |
583 | ✗ | fp_dbg ("Sensor type : TCS3, width x height: %hu x %hu", width, height); /* 360x248 --- 270x186 must be set */ | |
584 | ✗ | BUG_ON (height != 360); | |
585 | ✗ | img_class->img_width = 186; | |
586 | ✗ | img_class->img_height = 270; | |
587 | ✗ | break; | |
588 | |||
589 | 1 | case 192: | |
590 | 1 | fp_dbg ("Sensor type : TCS4x, width x height: %hu x %hu", width, height); /* 512x192 --- 384x144 must be set */ | |
591 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | BUG_ON (height != 512); |
592 | 1 | img_class->img_width = 144; | |
593 | 1 | img_class->img_height = 384; | |
594 | 1 | break; | |
595 | |||
596 | ✗ | case 144: | |
597 | ✗ | fp_dbg ("Sensor type : TCS5x, width x height: %hu x %hu", width, height); /* 512x144 --- 384x108 must be set */ | |
598 | ✗ | BUG_ON (height != 512); | |
599 | ✗ | img_class->img_width = 108; | |
600 | ✗ | img_class->img_height = 384; | |
601 | ✗ | break; | |
602 | |||
603 | ✗ | default: | |
604 | ✗ | fp_dbg ("Sensor type : Unknown"); | |
605 | |||
606 | ✗ | fpi_ssm_mark_failed (transfer->ssm, | |
607 | fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, | ||
608 | "Unknown sensor type (reported size %dx%d)", | ||
609 | width, height)); | ||
610 | |||
611 | ✗ | return; | |
612 | } | ||
613 | |||
614 | 2 | self->expected_image_size = img_class->img_width * img_class->img_height; | |
615 | 2 | self->image_bits = g_malloc0 (self->expected_image_size * 2); | |
616 | } | ||
617 | |||
618 | 12 | fpi_ssm_next_state (transfer->ssm); | |
619 | } | ||
620 | |||
621 | static void | ||
622 | 24 | activate_run_state (FpiSsm *ssm, FpDevice *dev) | |
623 | { | ||
624 | 24 | FpiUsbTransfer *transfer; | |
625 | 24 | FpImageDevice *idev = FP_IMAGE_DEVICE (dev); | |
626 | 24 | FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); | |
627 | |||
628 |
6/7✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
|
24 | switch (fpi_ssm_get_cur_state (ssm)) |
629 | { | ||
630 | 4 | case ACTIVATE_CONTROL_REQ_1: | |
631 | case ACTIVATE_CONTROL_REQ_2: | ||
632 | { | ||
633 | 4 | transfer = fpi_usb_transfer_new (dev); | |
634 | |||
635 | 4 | fpi_usb_transfer_fill_control (transfer, | |
636 | G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, | ||
637 | G_USB_DEVICE_REQUEST_TYPE_VENDOR, | ||
638 | G_USB_DEVICE_RECIPIENT_DEVICE, | ||
639 | 0x0c, 0x100, 0x0400, 1); | ||
640 | 4 | transfer->buffer[0] = '\0'; | |
641 | 4 | transfer->ssm = ssm; | |
642 | 4 | fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, | |
643 | fpi_ssm_usb_transfer_cb, NULL); | ||
644 | } | ||
645 | 4 | break; | |
646 | |||
647 | 2 | case ACTIVATE_INIT_1: | |
648 | 2 | upektc_img_submit_req (ssm, idev, upek2020_init_1, sizeof (upek2020_init_1), | |
649 | 0, init_reqs_cb); | ||
650 | 2 | break; | |
651 | |||
652 | 2 | case ACTIVATE_INIT_2: | |
653 | 2 | upektc_img_submit_req (ssm, idev, upek2020_init_2, sizeof (upek2020_init_2), | |
654 | 0, init_reqs_cb); | ||
655 | 2 | break; | |
656 | |||
657 | 2 | case ACTIVATE_INIT_3: | |
658 | 2 | upektc_img_submit_req (ssm, idev, upek2020_init_3, sizeof (upek2020_init_3), | |
659 | 0, init_reqs_cb); | ||
660 | 2 | break; | |
661 | |||
662 | 2 | case ACTIVATE_INIT_4: | |
663 | 2 | upektc_img_submit_req (ssm, idev, upek2020_init_4, sizeof (upek2020_init_4), | |
664 | 2 | self->seq, init_reqs_cb); | |
665 | /* Seq should be updated after 4th init */ | ||
666 | 2 | self->seq++; | |
667 | 2 | break; | |
668 | |||
669 | 12 | case ACTIVATE_READ_CTRL_RESP_1: | |
670 | case ACTIVATE_READ_CTRL_RESP_2: | ||
671 | case ACTIVATE_READ_INIT_1_RESP: | ||
672 | case ACTIVATE_READ_INIT_2_RESP: | ||
673 | case ACTIVATE_READ_INIT_3_RESP: | ||
674 | case ACTIVATE_READ_INIT_4_RESP: | ||
675 | 12 | upektc_img_read_data (ssm, idev, SHORT_RESPONSE_SIZE, 0, init_read_data_cb); | |
676 | 12 | break; | |
677 | } | ||
678 | 24 | } | |
679 | |||
680 | static void | ||
681 | 2 | activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) | |
682 | { | ||
683 | 2 | FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); | |
684 | |||
685 | 2 | fpi_image_device_activate_complete (dev, error); | |
686 | |||
687 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!error) |
688 | 2 | start_capture (dev); | |
689 | 2 | } | |
690 | |||
691 | static void | ||
692 | 2 | dev_activate (FpImageDevice *dev) | |
693 | { | ||
694 | 2 | FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); | |
695 | 2 | FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, | |
696 | ACTIVATE_NUM_STATES); | ||
697 | |||
698 | 2 | self->seq = 0; | |
699 | 2 | fpi_ssm_start (ssm, activate_sm_complete); | |
700 | 2 | } | |
701 | |||
702 | static void | ||
703 | 2 | dev_deactivate (FpImageDevice *dev) | |
704 | { | ||
705 | 2 | FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); | |
706 | |||
707 | 2 | self->deactivating = TRUE; | |
708 | 2 | } | |
709 | |||
710 | static void | ||
711 | 2 | dev_init (FpImageDevice *dev) | |
712 | { | ||
713 | 2 | GError *error = NULL; | |
714 | |||
715 | /* TODO check that device has endpoints we're using */ | ||
716 | |||
717 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error)) |
718 | { | ||
719 | ✗ | fpi_image_device_open_complete (dev, error); | |
720 | ✗ | return; | |
721 | } | ||
722 | |||
723 | 2 | fpi_image_device_open_complete (dev, NULL); | |
724 | } | ||
725 | |||
726 | static void | ||
727 | 2 | dev_deinit (FpImageDevice *dev) | |
728 | { | ||
729 | 2 | FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); | |
730 | 2 | GError *error = NULL; | |
731 | |||
732 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | g_clear_pointer (&self->image_bits, g_free); |
733 | 2 | g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), | |
734 | 0, 0, &error); | ||
735 | 2 | fpi_image_device_close_complete (dev, error); | |
736 | 2 | } | |
737 | |||
738 | static int | ||
739 | 2 | discover (GUsbDevice *usb_device) | |
740 | { | ||
741 | 2 | gint16 pid = g_usb_device_get_pid (usb_device); | |
742 | 2 | gint16 bcd = g_usb_device_get_release (usb_device); | |
743 | |||
744 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (pid == 0x2020 && bcd == 1) |
745 | return 100; | ||
746 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (pid == 0x2016 && bcd == 2) |
747 | 2 | return 100; | |
748 | |||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | static const FpIdEntry id_table[] = { | ||
753 | { .vid = 0x147e, .pid = 0x2016, }, | ||
754 | { .vid = 0x147e, .pid = 0x2020, }, | ||
755 | { .vid = 0, .pid = 0, .driver_data = 0 }, | ||
756 | }; | ||
757 | |||
758 | static void | ||
759 | 2 | fpi_device_upektc_img_init (FpiDeviceUpektcImg *self) | |
760 | { | ||
761 | 2 | } | |
762 | static void | ||
763 | 120 | fpi_device_upektc_img_class_init (FpiDeviceUpektcImgClass *klass) | |
764 | { | ||
765 | 120 | FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); | |
766 | 120 | FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); | |
767 | |||
768 | 120 | dev_class->id = "upektc_img"; | |
769 | 120 | dev_class->full_name = "Upek TouchChip Fingerprint Coprocessor"; | |
770 | 120 | dev_class->type = FP_DEVICE_TYPE_USB; | |
771 | 120 | dev_class->id_table = id_table; | |
772 | 120 | dev_class->scan_type = FP_SCAN_TYPE_SWIPE; | |
773 | 120 | dev_class->usb_discover = discover; | |
774 | |||
775 | 120 | img_class->img_open = dev_init; | |
776 | 120 | img_class->img_close = dev_deinit; | |
777 | 120 | img_class->activate = dev_activate; | |
778 | 120 | img_class->deactivate = dev_deactivate; | |
779 | |||
780 | 120 | img_class->bz3_threshold = 20; | |
781 | |||
782 | 120 | img_class->img_width = -1; | |
783 | 120 | img_class->img_height = -1; | |
784 | } | ||
785 |