GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/nb1010.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 165 186 88.7%
Functions: 20 20 100.0%
Branches: 30 47 63.8%

Line Branch Exec Source
1 /*
2 * Next Biometrics driver for libfprint
3 *
4 * Copyright (C) 2021 Huan Wang <fredwanghuan@gmail.com>
5 * Copyright (C) 2011-2012 Andrej Krutak <dev@andree.sk>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #define FP_COMPONENT "nb1010"
23 #include "fpi-log.h"
24
25 #include "drivers_api.h"
26
27 #define FRAME_HEIGHT 180
28 #define FRAME_WIDTH 256
29
30 #define NB1010_EP_OUT 0x02 | FPI_USB_ENDPOINT_OUT
31 #define NB1010_EP_IN 0x03 | FPI_USB_ENDPOINT_IN
32
33 #define NB1010_SENSITIVITY_BIT 12
34
35 #define NB1010_CMD_RECV_LEN 16
36 #define NB1010_CAPTURE_RECV_LEN 540
37 #define NB1010_CAPTURE_HEADER_LEN 25
38
39 #define NB1010_LINE_PER_PARTIAL 2
40 #define NB1010_N_PARTIAL (FRAME_HEIGHT / NB1010_LINE_PER_PARTIAL)
41
42 #define NB1010_DEFAULT_TIMEOUT 500
43 #define NB1010_TRANSITION_DELAY 50
44
45 /* Loop ssm states */
46 enum {
47 M_WAIT_PRINT,
48 M_REQUEST_PRINT,
49 M_CHECK_PRINT,
50 M_READ_PRINT_PRESTART,
51 M_READ_PRINT_START,
52 M_READ_PRINT_POLL,
53 M_SUBMIT_PRINT,
54
55 /* Number of states */
56 M_LOOP_NUM_STATES,
57 };
58
59 /*
60 * The Follow Commands are obtained by decoding the usbcap, so it does not expose all the command available to the device.
61 * Known:
62 * 1. every command starts with 0x80
63 * 2. second byte is the comand, third byte is the seqence nubmer, init with rand, gets incremented
64 * everytime a new instruction is sent to the device. However device does not care or check the sequence, just echo back
65 * whatever chosen by the host.
66 * 3. cmd: 0x07 check, expect [0x80, 0x29...] as response
67 * 4. cmd: 0x16 ???, expect [0x80, 0x20...] as response. Happens during device init.
68 * 5. cmd: 0x13 print device, expect [0x80, 0x23...] as response. Response contains the device string
69 * 6. cmd: 0x38 check finger, expect [0x80, 0x37...] as response. The 14th byte indicate whether finger present [0-255]
70 * 7. cmd: 0x0d ???, expect [0x80, 0x20...] as response. Happens before capture.
71 * 8. cmd: 0x12 capture, expect [0x80, 0x20...] as response. After capture read 90 times in sequence to get all the frame.
72 */
73
74 static guint8 nb1010_cmd_check_finger[] = {
75 0x80, 0x38, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
76 };
77
78 /* pre capture, dont know what does it do, but appears everytime a capture begins */
79 static guint8 nb1010_cmd_precapture[] = {
80 0x80, 0x0d, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
81 };
82
83 static guint8 nb1010_cmd_capture[] = {
84 0x80, 0x12, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,
85 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
88 };
89
90 struct _FpiDeviceNb1010
91 {
92 FpImageDevice parent;
93 FpiSsm *ssm;
94 guint8 *scanline_buf;
95 gboolean deactivating;
96 int partial_received;
97 };
98 G_DECLARE_FINAL_TYPE (FpiDeviceNb1010, fpi_device_nb1010, FPI, DEVICE_NB1010, FpImageDevice);
99
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 (FpiDeviceNb1010, fpi_device_nb1010, FP_TYPE_IMAGE_DEVICE);
100
101 static void
102 1 nb1010_dev_init (FpImageDevice *dev)
103 {
104 1 FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
105 1 GError *error = NULL;
106
107 1 g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
108
109 1 self->scanline_buf = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT);
110
111 1 fpi_image_device_open_complete (dev, error);
112 1 fp_dbg ("nb1010 Initialized");
113 1 }
114
115 static void
116 1 nb1010_dev_deinit (FpImageDevice *dev)
117 {
118 1 FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
119 1 GError *error = NULL;
120
121
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_clear_pointer (&self->scanline_buf, g_free);
122
123 1 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
124 1 fpi_image_device_close_complete (dev, error);
125 1 fp_dbg ("nb1010 Deinitialized");
126 1 }
127
128 static void
129 1 nb1010_dev_activate (FpImageDevice *dev)
130 {
131 1 FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
132
133 1 self->deactivating = FALSE;
134
135 1 fpi_image_device_activate_complete (dev, NULL);
136 1 fp_dbg ("nb1010 Activated");
137 1 }
138
139 static void
140 1 nb1010_dev_deactivated (FpImageDevice *dev, GError * err)
141 {
142 1 fpi_image_device_deactivate_complete (dev, err);
143 1 fp_dbg ("nb1010 Deactivated");
144 1 }
145
146 static void
147 1 nb1010_dev_deactivate (FpImageDevice *dev)
148 {
149 1 FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
150
151 1 self->deactivating = TRUE;
152
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (self->ssm == NULL)
153 1 nb1010_dev_deactivated (dev, NULL);
154 1 }
155
156 static void
157 1 nb1010_request_fingerprint (FpiDeviceNb1010 *dev)
158 {
159 1 FpiUsbTransfer *transfer = NULL;
160
161 1 transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
162 1 transfer->short_is_error = TRUE;
163 1 transfer->ssm = dev->ssm;
164
165 1 fpi_usb_transfer_fill_bulk_full (transfer, NB1010_EP_OUT,
166 nb1010_cmd_check_finger, G_N_ELEMENTS (nb1010_cmd_check_finger),
167 NULL);
168 1 fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
169 fpi_device_get_cancellable (FP_DEVICE (dev)),
170 fpi_ssm_usb_transfer_cb, NULL);
171 1 }
172
173 static void
174 1 nb1010_check_fingerprint_cb (FpiUsbTransfer *transfer, FpDevice *dev,
175 gpointer unused_data, GError *error)
176 {
177 1 FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
178
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (error)
180 {
181 fpi_ssm_mark_failed (transfer->ssm, error);
182 return;
183 }
184
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (self->deactivating)
185 {
186 fpi_ssm_mark_completed (transfer->ssm);
187 return;
188 }
189
190
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (transfer->buffer[NB1010_SENSITIVITY_BIT] > 0x30)
191 1 fpi_ssm_next_state (transfer->ssm);
192 else
193 fpi_ssm_jump_to_state (transfer->ssm, M_WAIT_PRINT);
194 }
195
196 static void
197 1 nb1010_cmd_check_fingerprint (FpiDeviceNb1010 *dev)
198 {
199 1 FpiUsbTransfer *transfer = NULL;
200
201 1 transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
202 1 transfer->short_is_error = TRUE;
203 1 transfer->ssm = dev->ssm;
204
205 1 fpi_usb_transfer_fill_bulk (transfer, NB1010_EP_IN, NB1010_CMD_RECV_LEN);
206 1 fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
207 fpi_device_get_cancellable (FP_DEVICE (dev)),
208 nb1010_check_fingerprint_cb, NULL);
209 1 }
210
211 static void
212 2 nb1010_read_ignore_data_cb (FpiUsbTransfer *transfer, FpDevice *dev,
213 gpointer unused_data, GError *error)
214 {
215 2 FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
216 2 FpiUsbTransfer *new_transfer = NULL;
217
218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (error)
219 {
220 fpi_ssm_mark_failed (transfer->ssm, error);
221 return;
222 }
223
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (self->deactivating)
224 {
225 fpi_ssm_mark_completed (transfer->ssm);
226 return;
227 }
228
229 2 new_transfer = fpi_usb_transfer_new ( dev );
230 2 new_transfer->short_is_error = TRUE;
231 2 new_transfer->ssm = transfer->ssm;
232
233 2 fpi_usb_transfer_fill_bulk (new_transfer, NB1010_EP_IN, NB1010_CMD_RECV_LEN);
234 2 fpi_usb_transfer_submit (new_transfer, NB1010_DEFAULT_TIMEOUT,
235 fpi_device_get_cancellable (FP_DEVICE (dev)),
236 fpi_ssm_usb_transfer_cb, NULL);
237 }
238
239 static void
240 2 nb1010_write_ignore_read (FpiDeviceNb1010 *dev, guint8 *buf, gsize len)
241 {
242 2 FpiUsbTransfer *transfer = NULL;
243
244 2 transfer = fpi_usb_transfer_new (FP_DEVICE ( dev));
245 2 transfer->short_is_error = TRUE;
246 2 transfer->ssm = dev->ssm;
247
248 2 fpi_usb_transfer_fill_bulk_full (transfer, NB1010_EP_OUT, buf, len, NULL);
249 2 fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
250 fpi_device_get_cancellable (FP_DEVICE (dev)),
251 nb1010_read_ignore_data_cb, NULL);
252 2 }
253
254
255 static void
256 90 nb1010_read_capture_cb (FpiUsbTransfer *transfer, FpDevice *dev,
257 gpointer unused_data, GError *error)
258 {
259 90 FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
260
261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 if (error)
262 {
263 fpi_ssm_mark_failed (transfer->ssm, error);
264 return;
265 }
266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 if (self->deactivating)
267 {
268 fpi_ssm_mark_completed (transfer->ssm);
269 return;
270 }
271
272
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 g_assert (transfer->actual_length == NB1010_CAPTURE_RECV_LEN);
273
274 90 size_t offset = self->partial_received * NB1010_LINE_PER_PARTIAL * FRAME_WIDTH;
275
276 90 memcpy (self->scanline_buf + offset,
277 90 transfer->buffer + NB1010_CAPTURE_HEADER_LEN, NB1010_LINE_PER_PARTIAL * FRAME_WIDTH);
278
279 90 self->partial_received++;
280
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 89 times.
90 if (self->partial_received == NB1010_N_PARTIAL)
281 {
282 1 fpi_ssm_next_state (transfer->ssm);
283 1 return;
284 }
285
286 89 fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer), NB1010_DEFAULT_TIMEOUT,
287 fpi_device_get_cancellable (FP_DEVICE (dev)),
288 nb1010_read_capture_cb, NULL);
289 }
290
291 static void
292 1 nb1010_read_capture (FpiDeviceNb1010 *dev)
293 {
294 1 FpiUsbTransfer *transfer = NULL;
295
296 1 transfer = fpi_usb_transfer_new ( FP_DEVICE ( dev));
297 1 transfer->short_is_error = TRUE;
298 1 transfer->ssm = dev->ssm;
299
300 1 fpi_usb_transfer_fill_bulk (transfer, NB1010_EP_IN, NB1010_CAPTURE_RECV_LEN);
301 1 fpi_usb_transfer_submit (transfer, NB1010_DEFAULT_TIMEOUT,
302 fpi_device_get_cancellable (FP_DEVICE (dev)),
303 nb1010_read_capture_cb, NULL);
304 1 }
305
306 static int
307 1 submit_image (FpiSsm *ssm,
308 FpImageDevice *dev)
309 {
310 1 FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
311 1 FpImage *img;
312
313 1 img = fp_image_new (FRAME_WIDTH, FRAME_HEIGHT);
314
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (img == NULL)
315 return 0;
316
317 1 memcpy (img->data, self->scanline_buf, FRAME_WIDTH * FRAME_HEIGHT);
318 1 fpi_image_device_image_captured (dev, img);
319
320 1 return 1;
321 }
322
323 static void
324 1 m_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
325 {
326 1 fp_dbg ("nb1010 ssm complete cb");
327
328 1 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
329 1 FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (_dev);
330
331 1 self->ssm = NULL;
332
333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (self->deactivating)
334 nb1010_dev_deactivated (dev, error);
335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 else if (error != NULL)
336 fpi_image_device_session_error (dev, error);
337 1 }
338
339 static void
340 7 m_loop_state (FpiSsm *ssm, FpDevice *_dev)
341 {
342 7 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
343 7 FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (_dev);
344
345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (self->deactivating)
346 {
347 fp_dbg ("deactivating, marking completed");
348 fpi_ssm_mark_completed (ssm);
349 return;
350 }
351
352
7/8
✓ 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 taken 1 times.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
7 switch (fpi_ssm_get_cur_state (ssm))
353 {
354 1 case M_WAIT_PRINT:
355 /* Wait fingerprint scanning */
356 1 fpi_ssm_next_state_delayed (ssm, NB1010_TRANSITION_DELAY);
357 1 break;
358
359 1 case M_REQUEST_PRINT:
360 1 nb1010_request_fingerprint (self);
361 1 break;
362
363 1 case M_CHECK_PRINT:
364 1 nb1010_cmd_check_fingerprint (self);
365 1 break;
366
367 1 case M_READ_PRINT_PRESTART:
368 1 fpi_image_device_report_finger_status (dev, TRUE);
369 1 nb1010_write_ignore_read (self, nb1010_cmd_precapture, G_N_ELEMENTS (nb1010_cmd_precapture));
370 1 break;
371
372 1 case M_READ_PRINT_START:
373 1 self->partial_received = 0;
374 1 nb1010_write_ignore_read (self, nb1010_cmd_capture, G_N_ELEMENTS (nb1010_cmd_capture));
375 1 break;
376
377 1 case M_READ_PRINT_POLL:
378 1 nb1010_read_capture (self);
379 1 break;
380
381 1 case M_SUBMIT_PRINT:
382
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (submit_image (ssm, dev))
383 {
384 1 fpi_ssm_mark_completed (ssm);
385 1 fpi_image_device_report_finger_status (dev, FALSE);
386 }
387 else
388 {
389 fpi_ssm_jump_to_state (ssm, M_WAIT_PRINT);
390 }
391 break;
392
393 default:
394 g_assert_not_reached ();
395 }
396 }
397
398 static void
399 8 nb1010_dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
400 {
401 8 FpiDeviceNb1010 *self = FPI_DEVICE_NB1010 (dev);
402 8 FpiSsm *ssm_loop;
403
404
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
405 {
406 1 ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, M_LOOP_NUM_STATES);
407 1 self->ssm = ssm_loop;
408 1 fpi_ssm_start (ssm_loop, m_loop_complete);
409 }
410 8 }
411
412
413 static const FpIdEntry id_table[] = {
414 { .vid = 0x298d, .pid = 0x1010, },
415 { .vid = 0, .pid = 0, .driver_data = 0 },
416 };
417
418 static void
419 1 fpi_device_nb1010_init (FpiDeviceNb1010 *self)
420 {
421 1 }
422
423 static void
424 120 fpi_device_nb1010_class_init (FpiDeviceNb1010Class *klass)
425 {
426 120 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
427 120 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
428
429 120 dev_class->id = FP_COMPONENT;
430 120 dev_class->full_name = "NextBiometrics NB-1010-U";
431 120 dev_class->type = FP_DEVICE_TYPE_USB;
432 120 dev_class->id_table = id_table;
433 120 dev_class->scan_type = FP_SCAN_TYPE_PRESS;
434
435 120 img_class->img_height = FRAME_HEIGHT;
436 120 img_class->img_width = FRAME_WIDTH;
437
438 120 img_class->bz3_threshold = 24;
439
440 120 img_class->img_open = nb1010_dev_init;
441 120 img_class->img_close = nb1010_dev_deinit;
442 120 img_class->activate = nb1010_dev_activate;
443 120 img_class->deactivate = nb1010_dev_deactivate;
444 120 img_class->change_state = nb1010_dev_change_state;
445 }
446