GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/upektc.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 16 206 7.8%
Functions: 3 22 13.6%
Branches: 4 46 8.7%

Line Branch Exec Source
1 /*
2 * UPEK TouchChip driver for libfprint
3 * Copyright (C) 2007 Jan-Michael Brummer <buzz2@gmx.de>
4 * Copyright (C) 2012 Vasily Khoruzhick <anarsoul@gmail.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #define FP_COMPONENT "upektc"
22
23 #include "drivers_api.h"
24 #include "upektc.h"
25
26 #define UPEKTC_EP_IN (2 | FPI_USB_ENDPOINT_IN)
27 #define UPEKTC_EP_OUT (3 | FPI_USB_ENDPOINT_OUT)
28 #define UPEKET_EP_IN (1 | FPI_USB_ENDPOINT_IN)
29 #define UPEKET_EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
30 #define BULK_TIMEOUT 4000
31
32 struct _FpiDeviceUpektc
33 {
34 FpImageDevice parent;
35
36 gboolean deactivating;
37 const struct setup_cmd *setup_commands;
38 size_t setup_commands_len;
39 int ep_in;
40 int ep_out;
41 int init_idx;
42 int sum_threshold;
43 };
44 G_DECLARE_FINAL_TYPE (FpiDeviceUpektc, fpi_device_upektc, FPI, DEVICE_UPEKTC,
45 FpImageDevice);
46
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 (FpiDeviceUpektc, fpi_device_upektc, FP_TYPE_IMAGE_DEVICE);
47
48 enum upektc_driver_data {
49 UPEKTC_2015,
50 UPEKTC_3001,
51 };
52
53 static void start_capture (FpImageDevice *dev);
54 static void complete_deactivation (FpImageDevice *dev,
55 GError *error);
56 static void start_finger_detection (FpImageDevice *dev);
57
58 /****** INITIALIZATION/DEINITIALIZATION ******/
59
60 enum activate_states {
61 WRITE_INIT,
62 READ_DATA,
63 ACTIVATE_NUM_STATES,
64 };
65
66 static void
67 upektc_next_init_cmd (FpiSsm *ssm,
68 FpImageDevice *dev)
69 {
70 FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
71
72 self->init_idx += 1;
73 if (self->init_idx == self->setup_commands_len)
74 fpi_ssm_mark_completed (ssm);
75 else
76 fpi_ssm_jump_to_state (ssm, WRITE_INIT);
77 }
78
79 static void
80 write_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
81 gpointer user_data, GError *error)
82 {
83 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
84 FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
85
86 if (!error)
87 {
88 if (self->setup_commands[self->init_idx].response_len)
89 fpi_ssm_next_state (transfer->ssm);
90 else
91 upektc_next_init_cmd (transfer->ssm, dev);
92 }
93 else
94 {
95 fpi_ssm_mark_failed (transfer->ssm, error);
96 }
97 }
98
99 static void
100 read_init_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
101 gpointer user_data, GError *error)
102 {
103 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
104
105 if (!error)
106 upektc_next_init_cmd (transfer->ssm, dev);
107 else
108 fpi_ssm_mark_failed (transfer->ssm, error);
109 }
110
111 static void
112 activate_run_state (FpiSsm *ssm, FpDevice *dev)
113 {
114 FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
115
116 switch (fpi_ssm_get_cur_state (ssm))
117 {
118 case WRITE_INIT:
119 {
120 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
121
122 fpi_usb_transfer_fill_bulk_full (transfer,
123 self->ep_out,
124 (unsigned char *) self->setup_commands[self->init_idx].cmd,
125 UPEKTC_CMD_LEN,
126 NULL);
127 transfer->ssm = ssm;
128 transfer->short_is_error = TRUE;
129 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
130 write_init_cb, NULL);
131 }
132 break;
133
134 case READ_DATA:
135 {
136 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
137
138 fpi_usb_transfer_fill_bulk (transfer,
139 self->ep_in,
140 self->setup_commands[self->init_idx].response_len);
141 transfer->ssm = ssm;
142 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
143 read_init_data_cb, NULL);
144 }
145 break;
146 }
147 }
148
149 static void
150 activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
151 {
152 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
153
154 fpi_image_device_activate_complete (dev, error);
155
156 if (!error)
157 start_finger_detection (dev);
158 }
159
160
161 /****** FINGER PRESENCE DETECTION ******/
162
163 static int
164 finger_present (unsigned char *img, size_t len, int sum_threshold)
165 {
166 int i, sum;
167
168 sum = 0;
169
170 for (i = 0; i < len; i++)
171 if (img[i] < 160)
172 sum++;
173
174 fp_dbg ("finger_present: sum is %d", sum);
175 return sum < sum_threshold ? 0 : 1;
176 }
177
178 static void
179 finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
180 gpointer user_data, GError *error)
181 {
182 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
183 FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
184
185 if (error)
186 {
187 fp_dbg ("data transfer status %s", error->message);
188 fpi_image_device_session_error (dev, error);
189 return;
190 }
191
192 if (finger_present (transfer->buffer, IMAGE_SIZE, self->sum_threshold))
193 {
194 /* finger present, start capturing */
195 fpi_image_device_report_finger_status (dev, TRUE);
196 start_capture (dev);
197 }
198 else
199 {
200 /* no finger, poll for a new histogram */
201 start_finger_detection (dev);
202 }
203 }
204
205 static void
206 finger_det_cmd_cb (FpiUsbTransfer *t, FpDevice *device,
207 gpointer user_data, GError *error)
208 {
209 FpiUsbTransfer *transfer;
210 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
211 FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
212
213 if (error)
214 {
215 fp_dbg ("req transfer status %s", error->message);
216 fpi_image_device_session_error (dev, error);
217 return;
218 }
219
220 transfer = fpi_usb_transfer_new (device);
221 transfer->short_is_error = TRUE;
222 fpi_usb_transfer_fill_bulk (transfer, self->ep_in,
223 IMAGE_SIZE);
224 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
225 finger_det_data_cb, NULL);
226 }
227
228 static void
229 start_finger_detection (FpImageDevice *dev)
230 {
231 FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
232 FpiUsbTransfer *transfer;
233
234 G_DEBUG_HERE ();
235
236 if (self->deactivating)
237 {
238 complete_deactivation (dev, NULL);
239 return;
240 }
241
242 transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
243 transfer->short_is_error = TRUE;
244 fpi_usb_transfer_fill_bulk_full (transfer, self->ep_out,
245 (unsigned char *) scan_cmd,
246 UPEKTC_CMD_LEN, NULL);
247 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
248 finger_det_cmd_cb, NULL);
249 }
250
251 /****** CAPTURE ******/
252
253 enum capture_states {
254 CAPTURE_WRITE_CMD,
255 CAPTURE_READ_DATA,
256 CAPTURE_NUM_STATES,
257 };
258
259 static void
260 capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
261 gpointer user_data, GError *error)
262 {
263 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
264 FpImage *img;
265
266 if (error)
267 {
268 fp_dbg ("request is not completed, %s", error->message);
269 fpi_ssm_mark_failed (transfer->ssm, error);
270 return;
271 }
272
273 img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
274 memcpy (img->data, transfer->buffer, IMAGE_SIZE);
275 fpi_image_device_image_captured (dev, img);
276 fpi_image_device_report_finger_status (dev, FALSE);
277 fpi_ssm_mark_completed (transfer->ssm);
278 }
279
280 static void
281 capture_run_state (FpiSsm *ssm, FpDevice *_dev)
282 {
283 FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (_dev);
284
285 switch (fpi_ssm_get_cur_state (ssm))
286 {
287 case CAPTURE_WRITE_CMD:
288 {
289 FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
290
291 fpi_usb_transfer_fill_bulk_full (transfer, self->ep_out,
292 (unsigned char *) scan_cmd,
293 UPEKTC_CMD_LEN, NULL);
294 transfer->ssm = ssm;
295 transfer->short_is_error = TRUE;
296 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
297 fpi_ssm_usb_transfer_cb, NULL);
298 }
299 break;
300
301 case CAPTURE_READ_DATA:
302 {
303 FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
304
305 fpi_usb_transfer_fill_bulk (transfer, self->ep_in,
306 IMAGE_SIZE);
307 transfer->ssm = ssm;
308 transfer->short_is_error = TRUE;
309 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
310 capture_read_data_cb, NULL);
311 }
312 break;
313 }
314 ;
315 }
316
317 static void
318 capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
319 {
320 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
321 FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (_dev);
322
323 fp_dbg ("Capture completed");
324 if (self->deactivating)
325 complete_deactivation (dev, error);
326 else if (error)
327 fpi_image_device_session_error (dev, error);
328 else
329 start_finger_detection (dev);
330
331 }
332
333 static void
334 start_capture (FpImageDevice *dev)
335 {
336 FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
337 FpiSsm *ssm;
338
339 if (self->deactivating)
340 {
341 complete_deactivation (dev, NULL);
342 return;
343 }
344
345 ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, CAPTURE_NUM_STATES);
346 G_DEBUG_HERE ();
347 fpi_ssm_start (ssm, capture_sm_complete);
348 }
349
350 static void
351 dev_activate (FpImageDevice *dev)
352 {
353 FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
354 FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
355 ACTIVATE_NUM_STATES);
356
357 self->init_idx = 0;
358 fpi_ssm_start (ssm, activate_sm_complete);
359 }
360
361 static void
362 dev_deactivate (FpImageDevice *dev)
363 {
364 FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
365
366 self->deactivating = TRUE;
367 }
368
369 static void
370 complete_deactivation (FpImageDevice *dev, GError *error)
371 {
372 FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
373
374 G_DEBUG_HERE ();
375
376 self->deactivating = FALSE;
377 fpi_image_device_deactivate_complete (dev, error);
378 }
379
380 static void
381 dev_init (FpImageDevice *dev)
382 {
383 GError *error = NULL;
384 FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
385 guint64 driver_data = fpi_device_get_driver_data (FP_DEVICE (dev));
386
387 /* TODO check that device has endpoints we're using */
388
389 if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
390 {
391 fpi_image_device_open_complete (dev, error);
392 return;
393 }
394
395 switch (driver_data)
396 {
397 case UPEKTC_2015:
398 self->ep_in = UPEKTC_EP_IN;
399 self->ep_out = UPEKTC_EP_OUT;
400 self->setup_commands = upektc_setup_commands;
401 self->setup_commands_len = G_N_ELEMENTS (upektc_setup_commands);
402 self->sum_threshold = UPEKTC_SUM_THRESHOLD;
403 break;
404
405 case UPEKTC_3001:
406 self->ep_in = UPEKET_EP_IN;
407 self->ep_out = UPEKET_EP_OUT;
408 self->setup_commands = upeket_setup_commands;
409 self->setup_commands_len = G_N_ELEMENTS (upeket_setup_commands);
410 self->sum_threshold = UPEKET_SUM_THRESHOLD;
411 break;
412
413 default:
414 fp_err ("Device variant %" G_GUINT64_FORMAT " is not known", driver_data);
415 g_assert_not_reached ();
416 fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
417 return;
418 }
419 fpi_image_device_open_complete (dev, NULL);
420 }
421
422 static void
423 dev_deinit (FpImageDevice *dev)
424 {
425 GError *error = NULL;
426
427 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
428 0, 0, &error);
429 fpi_image_device_close_complete (dev, error);
430 }
431
432 static const FpIdEntry id_table[] = {
433 { .vid = 0x0483, .pid = 0x2015, .driver_data = UPEKTC_2015 },
434 { .vid = 0x0483, .pid = 0x2017, .driver_data = UPEKTC_2015 },
435 { .vid = 0x147e, .pid = 0x3001, .driver_data = UPEKTC_3001 },
436 { .vid = 0, .pid = 0, .driver_data = 0 },
437 };
438
439 static void
440 fpi_device_upektc_init (FpiDeviceUpektc *self)
441 {
442 }
443 static void
444 120 fpi_device_upektc_class_init (FpiDeviceUpektcClass *klass)
445 {
446 120 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
447 120 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
448
449 120 dev_class->id = "upektc";
450 120 dev_class->full_name = "UPEK TouchChip/Eikon Touch 300";
451 120 dev_class->type = FP_DEVICE_TYPE_USB;
452 120 dev_class->id_table = id_table;
453 120 dev_class->scan_type = FP_SCAN_TYPE_PRESS;
454
455 120 img_class->img_open = dev_init;
456 120 img_class->img_close = dev_deinit;
457 120 img_class->activate = dev_activate;
458 120 img_class->deactivate = dev_deactivate;
459
460 120 img_class->bz3_threshold = 30;
461
462 120 img_class->img_width = IMAGE_WIDTH;
463 120 img_class->img_height = IMAGE_HEIGHT;
464 }
465