Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Digital Persona U.are.U 4000/4000B/4500 driver for libfprint | ||
3 | * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org> | ||
4 | * Copyright (C) 2012 Timo Teräs <timo.teras@iki.fi> | ||
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 "uru4000" | ||
22 | |||
23 | #include <nss.h> | ||
24 | #include <pk11pub.h> | ||
25 | |||
26 | #include "drivers_api.h" | ||
27 | |||
28 | #define EP_INTR (1 | FPI_USB_ENDPOINT_IN) | ||
29 | #define EP_DATA (2 | FPI_USB_ENDPOINT_IN) | ||
30 | #define USB_RQ 0x04 | ||
31 | #define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | FPI_USB_ENDPOINT_IN) | ||
32 | #define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | FPI_USB_ENDPOINT_OUT) | ||
33 | #define CTRL_TIMEOUT 5000 | ||
34 | #define BULK_TIMEOUT 5000 | ||
35 | #define IRQ_LENGTH 64 | ||
36 | #define CR_LENGTH 16 | ||
37 | |||
38 | #define IMAGE_HEIGHT 290 | ||
39 | #define IMAGE_WIDTH 384 | ||
40 | |||
41 | #define ENC_THRESHOLD 5000 | ||
42 | |||
43 | enum { | ||
44 | IRQDATA_SCANPWR_ON = 0x56aa, | ||
45 | IRQDATA_FINGER_ON = 0x0101, | ||
46 | IRQDATA_FINGER_OFF = 0x0200, | ||
47 | IRQDATA_DEATH = 0x0800, | ||
48 | }; | ||
49 | |||
50 | enum { | ||
51 | REG_HWSTAT = 0x07, | ||
52 | REG_SCRAMBLE_DATA_INDEX = 0x33, | ||
53 | REG_SCRAMBLE_DATA_KEY = 0x34, | ||
54 | REG_MODE = 0x4e, | ||
55 | REG_DEVICE_INFO = 0xf0, | ||
56 | /* firmware starts at 0x100 */ | ||
57 | REG_RESPONSE = 0x2000, | ||
58 | REG_CHALLENGE = 0x2010, | ||
59 | }; | ||
60 | |||
61 | enum { | ||
62 | MODE_INIT = 0x00, | ||
63 | MODE_AWAIT_FINGER_ON = 0x10, | ||
64 | MODE_AWAIT_FINGER_OFF = 0x12, | ||
65 | MODE_CAPTURE = 0x20, | ||
66 | MODE_CAPTURE_AUX = 0x30, | ||
67 | MODE_OFF = 0x70, | ||
68 | MODE_READY = 0x80, | ||
69 | }; | ||
70 | |||
71 | enum { | ||
72 | MS_KBD, | ||
73 | MS_INTELLIMOUSE, | ||
74 | MS_STANDALONE, | ||
75 | MS_STANDALONE_V2, | ||
76 | DP_URU4000, | ||
77 | DP_URU4000B, | ||
78 | }; | ||
79 | |||
80 | static const struct uru4k_dev_profile | ||
81 | { | ||
82 | const char *name; | ||
83 | gboolean auth_cr; | ||
84 | gboolean image_not_flipped; | ||
85 | } uru4k_dev_info[] = { | ||
86 | [MS_KBD] = { | ||
87 | .name = "Microsoft Keyboard with Fingerprint Reader", | ||
88 | .auth_cr = FALSE, | ||
89 | }, | ||
90 | [MS_INTELLIMOUSE] = { | ||
91 | .name = "Microsoft Wireless IntelliMouse with Fingerprint Reader", | ||
92 | .auth_cr = FALSE, | ||
93 | }, | ||
94 | [MS_STANDALONE] = { | ||
95 | .name = "Microsoft Fingerprint Reader", | ||
96 | .auth_cr = FALSE, | ||
97 | }, | ||
98 | [MS_STANDALONE_V2] = { | ||
99 | .name = "Microsoft Fingerprint Reader v2", | ||
100 | .auth_cr = TRUE, | ||
101 | }, | ||
102 | [DP_URU4000] = { | ||
103 | .name = "Digital Persona U.are.U 4000", | ||
104 | .auth_cr = FALSE, | ||
105 | }, | ||
106 | [DP_URU4000B] = { | ||
107 | .name = "Digital Persona U.are.U 4000B", | ||
108 | .auth_cr = FALSE, | ||
109 | .image_not_flipped = TRUE, /* See comment in the code where it is used. */ | ||
110 | }, | ||
111 | }; | ||
112 | |||
113 | typedef void (*irq_cb_fn)(FpImageDevice *dev, | ||
114 | GError *error, | ||
115 | uint16_t type, | ||
116 | void *user_data); | ||
117 | typedef void (*irqs_stopped_cb_fn)(FpImageDevice *dev); | ||
118 | |||
119 | struct _FpiDeviceUru4000 | ||
120 | { | ||
121 | FpImageDevice parent; | ||
122 | |||
123 | const struct uru4k_dev_profile *profile; | ||
124 | uint8_t interface; | ||
125 | FpiImageDeviceState activate_state; | ||
126 | unsigned char last_reg_rd[16]; | ||
127 | unsigned char last_hwstat; | ||
128 | |||
129 | GCancellable *irq_cancellable; | ||
130 | FpiUsbTransfer *img_transfer; | ||
131 | void *img_data; | ||
132 | int img_data_actual_length; | ||
133 | uint16_t img_lines_done, img_block; | ||
134 | GRand *rand; | ||
135 | uint32_t img_enc_seed; | ||
136 | |||
137 | irq_cb_fn irq_cb; | ||
138 | void *irq_cb_data; | ||
139 | irqs_stopped_cb_fn irqs_stopped_cb; | ||
140 | |||
141 | int rebootpwr_ctr; | ||
142 | int powerup_ctr; | ||
143 | unsigned char powerup_hwstat; | ||
144 | |||
145 | int scanpwr_irq_timeouts; | ||
146 | GSource *scanpwr_irq_timeout; | ||
147 | |||
148 | int fwfixer_offset; | ||
149 | unsigned char fwfixer_value; | ||
150 | |||
151 | CK_MECHANISM_TYPE cipher; | ||
152 | PK11SlotInfo *slot; | ||
153 | PK11SymKey *symkey; | ||
154 | SECItem *param; | ||
155 | }; | ||
156 | G_DECLARE_FINAL_TYPE (FpiDeviceUru4000, fpi_device_uru4000, FPI, DEVICE_URU4000, | ||
157 | FpImageDevice); | ||
158 |
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 (FpiDeviceUru4000, fpi_device_uru4000, FP_TYPE_IMAGE_DEVICE); |
159 | |||
160 | /* For 2nd generation MS devices */ | ||
161 | static const unsigned char crkey[] = { | ||
162 | 0x79, 0xac, 0x91, 0x79, 0x5c, 0xa1, 0x47, 0x8e, | ||
163 | 0x98, 0xe0, 0x0f, 0x3c, 0x59, 0x8f, 0x5f, 0x4b, | ||
164 | }; | ||
165 | |||
166 | /***** REGISTER I/O *****/ | ||
167 | |||
168 | static void | ||
169 | 16 | write_regs (FpImageDevice *dev, uint16_t first_reg, | |
170 | uint16_t num_regs, unsigned char *values, | ||
171 | FpiUsbTransferCallback callback, | ||
172 | void *user_data) | ||
173 | { | ||
174 | 16 | FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); | |
175 | |||
176 | 16 | transfer->short_is_error = TRUE; | |
177 | 16 | fpi_usb_transfer_fill_control (transfer, | |
178 | G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, | ||
179 | G_USB_DEVICE_REQUEST_TYPE_VENDOR, | ||
180 | G_USB_DEVICE_RECIPIENT_DEVICE, | ||
181 | USB_RQ, first_reg, 0, | ||
182 | num_regs); | ||
183 | 16 | memcpy (transfer->buffer, values, num_regs); | |
184 | 16 | fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, callback, user_data); | |
185 | 16 | } | |
186 | |||
187 | static void | ||
188 | 8 | write_reg (FpImageDevice *dev, uint16_t reg, | |
189 | unsigned char value, | ||
190 | FpiUsbTransferCallback callback, | ||
191 | void *user_data) | ||
192 | { | ||
193 | 8 | write_regs (dev, reg, 1, &value, callback, user_data); | |
194 | } | ||
195 | |||
196 | static void | ||
197 | 10 | read_regs (FpImageDevice *dev, uint16_t first_reg, | |
198 | uint16_t num_regs, | ||
199 | FpiUsbTransferCallback callback, | ||
200 | void *user_data) | ||
201 | { | ||
202 | 10 | FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); | |
203 | |||
204 | 10 | fpi_usb_transfer_fill_control (transfer, | |
205 | G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, | ||
206 | G_USB_DEVICE_REQUEST_TYPE_VENDOR, | ||
207 | G_USB_DEVICE_RECIPIENT_DEVICE, | ||
208 | USB_RQ, first_reg, 0, num_regs); | ||
209 | 10 | fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, callback, user_data); | |
210 | 10 | } | |
211 | |||
212 | /* | ||
213 | * HWSTAT | ||
214 | * | ||
215 | * This register has caused me a lot of headaches. It pretty much defines | ||
216 | * code flow, and if you don't get it right, the pretty lights don't come on. | ||
217 | * I think the situation is somewhat complicated by the fact that writing it | ||
218 | * doesn't affect the read results in the way you'd expect -- but then again | ||
219 | * it does have some obvious effects. Here's what we know | ||
220 | * | ||
221 | * BIT 7: LOW POWER MODE | ||
222 | * When this bit is set, the device is partially turned off or something. Some | ||
223 | * things, like firmware upload, need to be done in this state. But generally | ||
224 | * we want to clear this bit during late initialization, which can sometimes | ||
225 | * be tricky. | ||
226 | * | ||
227 | * BIT 2: SOMETHING WENT WRONG | ||
228 | * Not sure about this, but see the init function, as when we detect it, | ||
229 | * we reboot the device. Well, we mess with hwstat until this evil bit gets | ||
230 | * cleared. | ||
231 | * | ||
232 | * BIT 1: IRQ PENDING | ||
233 | * Just had a brainwave. This bit is set when the device is trying to deliver | ||
234 | * an interrupt to the host. Maybe? | ||
235 | */ | ||
236 | |||
237 | static void | ||
238 | 1 | response_cb (FpiUsbTransfer *transfer, FpDevice *dev, void *user_data, GError *error) | |
239 | { | ||
240 | /* NOTE: We could use the SSM function instead if we attached the ssm to the transfer! */ | ||
241 | 1 | FpiSsm *ssm = user_data; | |
242 | |||
243 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (!error) |
244 | 1 | fpi_ssm_next_state (ssm); | |
245 | else | ||
246 | ✗ | fpi_ssm_mark_failed (ssm, error); | |
247 | 1 | } | |
248 | |||
249 | static void | ||
250 | 1 | challenge_cb (FpiUsbTransfer *transfer, FpDevice *dev, void *user_data, GError *error) | |
251 | { | ||
252 | 1 | FpiSsm *ssm = user_data; | |
253 | 1 | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); | |
254 | 1 | unsigned char respdata[CR_LENGTH]; | |
255 | 1 | PK11Context *ctx; | |
256 | 1 | int outlen; | |
257 | |||
258 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
259 | { | ||
260 | ✗ | fpi_ssm_mark_failed (ssm, error); | |
261 | ✗ | return; | |
262 | } | ||
263 | |||
264 | /* submit response */ | ||
265 | /* produce response from challenge */ | ||
266 | 2 | ctx = PK11_CreateContextBySymKey (self->cipher, CKA_ENCRYPT, | |
267 | 1 | self->symkey, self->param); | |
268 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
2 | if (PK11_CipherOp (ctx, respdata, &outlen, CR_LENGTH, transfer->buffer, CR_LENGTH) != SECSuccess || |
269 | 1 | PK11_Finalize (ctx) != SECSuccess) | |
270 | { | ||
271 | ✗ | fp_err ("Failed to encrypt challenge data"); | |
272 | ✗ | error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "Failed to encrypt challenge data"); | |
273 | } | ||
274 | 1 | PK11_DestroyContext (ctx, PR_TRUE); | |
275 | |||
276 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (!error) |
277 | 1 | write_regs (FP_IMAGE_DEVICE (dev), REG_RESPONSE, CR_LENGTH, respdata, response_cb, ssm); | |
278 | else | ||
279 | ✗ | fpi_ssm_mark_failed (ssm, error); | |
280 | } | ||
281 | |||
282 | /* | ||
283 | * 2nd generation MS devices added an AES-based challenge/response | ||
284 | * authentication scheme, where the device challenges the authenticity of the | ||
285 | * driver. | ||
286 | */ | ||
287 | static void | ||
288 | 1 | sm_do_challenge_response (FpiSsm *ssm, | |
289 | FpImageDevice *dev) | ||
290 | { | ||
291 | 1 | G_DEBUG_HERE (); | |
292 | 1 | read_regs (dev, REG_CHALLENGE, CR_LENGTH, challenge_cb, ssm); | |
293 | 1 | } | |
294 | |||
295 | /***** INTERRUPT HANDLING *****/ | ||
296 | |||
297 | #define IRQ_HANDLER_IS_RUNNING(urudev) ((urudev)->irq_cancellable) | ||
298 | |||
299 | static void start_irq_handler (FpImageDevice *dev); | ||
300 | |||
301 | static void | ||
302 | 10 | irq_handler (FpiUsbTransfer *transfer, | |
303 | FpDevice *dev, | ||
304 | void *user_data, | ||
305 | GError *error) | ||
306 | { | ||
307 | 10 | FpImageDevice *imgdev = FP_IMAGE_DEVICE (dev); | |
308 | 10 | FpiDeviceUru4000 *urudev = FPI_DEVICE_URU4000 (dev); | |
309 | 10 | unsigned char *data = transfer->buffer; | |
310 | 10 | uint16_t type; | |
311 | |||
312 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | g_clear_object (&urudev->irq_cancellable); |
313 | |||
314 |
2/2✓ Branch 2 taken 2 times.
✓ Branch 3 taken 8 times.
|
10 | if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
315 | { | ||
316 | 2 | fp_dbg ("cancelled"); | |
317 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (urudev->irqs_stopped_cb) |
318 | 2 | urudev->irqs_stopped_cb (imgdev); | |
319 | 2 | urudev->irqs_stopped_cb = NULL; | |
320 | 2 | g_clear_error (&error); | |
321 | 2 | return; | |
322 | } | ||
323 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | else if (error) |
324 | { | ||
325 | ✗ | if (urudev->irq_cb) | |
326 | { | ||
327 | ✗ | urudev->irq_cb (imgdev, error, 0, urudev->irq_cb_data); | |
328 | } | ||
329 | else | ||
330 | { | ||
331 | ✗ | fp_dbg ("ignoring interrupt error: %s", error->message); | |
332 | ✗ | g_clear_error (&error); | |
333 | } | ||
334 | ✗ | return; | |
335 | } | ||
336 | |||
337 | 8 | start_irq_handler (imgdev); | |
338 | |||
339 | 8 | type = GUINT16_FROM_BE (*((uint16_t *) data)); | |
340 | 8 | fp_dbg ("recv irq type %04x", type); | |
341 | |||
342 | /* The 0800 interrupt seems to indicate imminent failure (0 bytes transfer) | ||
343 | * of the next scan. It still appears on occasion. */ | ||
344 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (type == IRQDATA_DEATH) |
345 | ✗ | fp_warn ("oh no! got the interrupt OF DEATH! expect things to go bad"); | |
346 | |||
347 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (urudev->irq_cb) |
348 | 8 | urudev->irq_cb (imgdev, NULL, type, urudev->irq_cb_data); | |
349 | else | ||
350 | ✗ | fp_dbg ("ignoring interrupt"); | |
351 | } | ||
352 | |||
353 | static void | ||
354 | 10 | start_irq_handler (FpImageDevice *dev) | |
355 | { | ||
356 | 10 | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); | |
357 | 10 | FpiUsbTransfer *transfer; | |
358 | |||
359 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | g_assert (self->irq_cancellable == NULL); |
360 | 10 | self->irq_cancellable = g_cancellable_new (); | |
361 | 10 | transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); | |
362 | 10 | transfer->ssm = NULL; | |
363 | 10 | transfer->short_is_error = TRUE; | |
364 | 10 | fpi_usb_transfer_fill_interrupt (transfer, | |
365 | EP_INTR, | ||
366 | IRQ_LENGTH); | ||
367 | 10 | fpi_usb_transfer_submit (transfer, 0, self->irq_cancellable, irq_handler, NULL); | |
368 | 10 | } | |
369 | |||
370 | static void | ||
371 | 2 | stop_irq_handler (FpImageDevice *dev, irqs_stopped_cb_fn cb) | |
372 | { | ||
373 | 2 | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); | |
374 | |||
375 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (self->irq_cancellable) |
376 | { | ||
377 | 2 | g_cancellable_cancel (self->irq_cancellable); | |
378 | 2 | self->irqs_stopped_cb = cb; | |
379 | } | ||
380 | else | ||
381 | { | ||
382 | ✗ | cb (dev); | |
383 | } | ||
384 | 2 | } | |
385 | |||
386 | /***** STATE CHANGING *****/ | ||
387 | |||
388 | static void execute_state_change (FpImageDevice *dev); | ||
389 | |||
390 | static void | ||
391 | 6 | finger_presence_irq_cb (FpImageDevice *dev, | |
392 | GError *error, | ||
393 | uint16_t type, | ||
394 | void *user_data) | ||
395 | { | ||
396 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (error) |
397 | ✗ | fpi_image_device_session_error (dev, error); | |
398 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
6 | else if (type == IRQDATA_FINGER_ON) |
399 | 2 | fpi_image_device_report_finger_status (dev, TRUE); | |
400 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | else if (type == IRQDATA_FINGER_OFF) |
401 | 2 | fpi_image_device_report_finger_status (dev, FALSE); | |
402 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | else if (type != IRQDATA_SCANPWR_ON) |
403 | ✗ | fp_warn ("ignoring unexpected interrupt %04x", type); | |
404 | 6 | } | |
405 | |||
406 | static void | ||
407 | 6 | change_state_write_reg_cb (FpiUsbTransfer *transfer, | |
408 | FpDevice *dev, | ||
409 | void *user_data, | ||
410 | GError *error) | ||
411 | { | ||
412 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (error) |
413 | ✗ | fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error); | |
414 | 6 | } | |
415 | |||
416 | static void | ||
417 | 16 | dev_change_state (FpImageDevice *dev, FpiImageDeviceState state) | |
418 | { | ||
419 | 16 | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); | |
420 | |||
421 | 16 | self->activate_state = state; | |
422 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
|
16 | if (self->img_transfer != NULL) |
423 | return; | ||
424 | |||
425 | 14 | execute_state_change (dev); | |
426 | } | ||
427 | |||
428 | /***** GENERIC STATE MACHINE HELPER FUNCTIONS *****/ | ||
429 | |||
430 | static void | ||
431 | 7 | sm_write_reg_cb (FpiUsbTransfer *transfer, | |
432 | FpDevice *dev, | ||
433 | void *user_data, | ||
434 | GError *error) | ||
435 | { | ||
436 | 7 | FpiSsm *ssm = user_data; | |
437 | |||
438 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (error) |
439 | ✗ | fpi_ssm_mark_failed (ssm, error); | |
440 | else | ||
441 | 7 | fpi_ssm_next_state (ssm); | |
442 | 7 | } | |
443 | |||
444 | static void | ||
445 | 7 | sm_write_regs (FpiSsm *ssm, | |
446 | FpImageDevice *dev, | ||
447 | uint16_t first_reg, | ||
448 | uint16_t num_regs, | ||
449 | void *data) | ||
450 | { | ||
451 | 7 | write_regs (dev, first_reg, num_regs, data, sm_write_reg_cb, ssm); | |
452 | 2 | } | |
453 | |||
454 | static void | ||
455 | 5 | sm_write_reg (FpiSsm *ssm, | |
456 | FpImageDevice *dev, | ||
457 | uint16_t reg, | ||
458 | unsigned char value) | ||
459 | { | ||
460 | 10 | sm_write_regs (ssm, dev, reg, 1, &value); | |
461 | } | ||
462 | |||
463 | static void | ||
464 | 9 | sm_read_reg_cb (FpiUsbTransfer *transfer, | |
465 | FpDevice *dev, | ||
466 | void *user_data, | ||
467 | GError *error) | ||
468 | { | ||
469 | 9 | FpiSsm *ssm = user_data; | |
470 | 9 | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); | |
471 | |||
472 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if (error) |
473 | { | ||
474 | ✗ | fpi_ssm_mark_failed (ssm, error); | |
475 | } | ||
476 | else | ||
477 | { | ||
478 | 9 | memcpy (self->last_reg_rd, transfer->buffer, transfer->actual_length); | |
479 | 9 | fp_dbg ("reg value %x", self->last_reg_rd[0]); | |
480 | 9 | fpi_ssm_next_state (ssm); | |
481 | } | ||
482 | 9 | } | |
483 | |||
484 | #define member_size(type, member) sizeof (((type *) 0)->member) | ||
485 | |||
486 | static void | ||
487 | 9 | sm_read_regs (FpiSsm *ssm, | |
488 | FpImageDevice *dev, | ||
489 | uint16_t reg, | ||
490 | uint16_t num_regs) | ||
491 | { | ||
492 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | g_assert (num_regs <= member_size (FpiDeviceUru4000, last_reg_rd)); |
493 | |||
494 | 9 | fp_dbg ("read %d regs at %x", num_regs, reg); | |
495 | 9 | read_regs (dev, reg, num_regs, sm_read_reg_cb, ssm); | |
496 | 9 | } | |
497 | |||
498 | static void | ||
499 | 5 | sm_read_reg (FpiSsm *ssm, | |
500 | FpImageDevice *dev, | ||
501 | uint16_t reg) | ||
502 | { | ||
503 | 5 | sm_read_regs (ssm, dev, reg, 1); | |
504 | 5 | } | |
505 | |||
506 | static void | ||
507 | 5 | sm_set_hwstat (FpiSsm *ssm, | |
508 | FpImageDevice *dev, | ||
509 | unsigned char value) | ||
510 | { | ||
511 | 5 | fp_dbg ("set %02x", value); | |
512 | 5 | sm_write_reg (ssm, dev, REG_HWSTAT, value); | |
513 | 5 | } | |
514 | |||
515 | /***** IMAGING LOOP *****/ | ||
516 | |||
517 | enum imaging_states { | ||
518 | IMAGING_CAPTURE, | ||
519 | IMAGING_SEND_INDEX, | ||
520 | IMAGING_READ_KEY, | ||
521 | IMAGING_DECODE, | ||
522 | IMAGING_REPORT_IMAGE, | ||
523 | IMAGING_NUM_STATES | ||
524 | }; | ||
525 | |||
526 | struct uru4k_image | ||
527 | { | ||
528 | uint8_t unknown_00[4]; | ||
529 | uint16_t num_lines; | ||
530 | uint8_t key_number; | ||
531 | uint8_t unknown_07[9]; | ||
532 | struct | ||
533 | { | ||
534 | uint8_t flags; | ||
535 | uint8_t num_lines; | ||
536 | } block_info[15]; | ||
537 | uint8_t unknown_2E[18]; | ||
538 | uint8_t data[IMAGE_HEIGHT][IMAGE_WIDTH]; | ||
539 | }; | ||
540 | |||
541 | static void | ||
542 | 2 | image_transfer_cb (FpiUsbTransfer *transfer, FpDevice *dev, | |
543 | gpointer user_data, GError *error) | ||
544 | { | ||
545 | 2 | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); | |
546 | 2 | FpiSsm *ssm = transfer->ssm; | |
547 | |||
548 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (error) |
549 | { | ||
550 | ✗ | fp_dbg ("error"); | |
551 | ✗ | fpi_ssm_mark_failed (ssm, error); | |
552 | } | ||
553 | else | ||
554 | { | ||
555 | 2 | self->img_data = g_memdup2 (transfer->buffer, sizeof (struct uru4k_image)); | |
556 | 2 | self->img_data_actual_length = transfer->actual_length; | |
557 | 2 | fpi_ssm_next_state (ssm); | |
558 | } | ||
559 | 2 | } | |
560 | |||
561 | enum { | ||
562 | BLOCKF_CHANGE_KEY = 0x80, | ||
563 | BLOCKF_NO_KEY_UPDATE = 0x04, | ||
564 | BLOCKF_ENCRYPTED = 0x02, | ||
565 | BLOCKF_NOT_PRESENT = 0x01, | ||
566 | }; | ||
567 | |||
568 | static uint32_t | ||
569 | 222720 | update_key (uint32_t key) | |
570 | { | ||
571 | /* linear feedback shift register | ||
572 | * taps at bit positions 1 3 4 7 11 13 20 23 26 29 32 */ | ||
573 | 222720 | uint32_t bit = key & 0x9248144d; | |
574 | |||
575 | 222720 | bit ^= bit << 16; | |
576 | 222720 | bit ^= bit << 8; | |
577 | 222720 | bit ^= bit << 4; | |
578 | 222720 | bit ^= bit << 2; | |
579 | 222720 | bit ^= bit << 1; | |
580 | 222720 | return (bit & 0x80000000) | (key >> 1); | |
581 | } | ||
582 | |||
583 | static uint32_t | ||
584 | 8 | do_decode (uint8_t *data, int num_bytes, uint32_t key) | |
585 | { | ||
586 | 8 | uint8_t xorbyte; | |
587 | 8 | int i; | |
588 | |||
589 |
2/2✓ Branch 0 taken 219640 times.
✓ Branch 1 taken 8 times.
|
219648 | for (i = 0; i < num_bytes - 1; i++) |
590 | { | ||
591 | /* calculate xor byte and update key */ | ||
592 | 219640 | xorbyte = ((key >> 4) & 1) << 0; | |
593 | 219640 | xorbyte |= ((key >> 8) & 1) << 1; | |
594 | 219640 | xorbyte |= ((key >> 11) & 1) << 2; | |
595 | 219640 | xorbyte |= ((key >> 14) & 1) << 3; | |
596 | 219640 | xorbyte |= ((key >> 18) & 1) << 4; | |
597 | 219640 | xorbyte |= ((key >> 21) & 1) << 5; | |
598 | 219640 | xorbyte |= ((key >> 24) & 1) << 6; | |
599 | 219640 | xorbyte |= ((key >> 29) & 1) << 7; | |
600 | 219640 | key = update_key (key); | |
601 | |||
602 | /* decrypt data */ | ||
603 | 219640 | data[i] = data[i + 1] ^ xorbyte; | |
604 | } | ||
605 | |||
606 | /* the final byte is implicitly zero */ | ||
607 | 8 | data[i] = 0; | |
608 | 8 | return update_key (key); | |
609 | } | ||
610 | |||
611 | static int | ||
612 | 2 | calc_dev2 (struct uru4k_image *img) | |
613 | { | ||
614 | 2 | uint8_t *b[2] = { NULL, NULL }; | |
615 | 2 | int res = 0, mean = 0, i, r, j, idx; | |
616 | |||
617 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | for (i = r = idx = 0; i < G_N_ELEMENTS (img->block_info) && idx < 2; i++) |
618 | { | ||
619 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (img->block_info[i].flags & BLOCKF_NOT_PRESENT) |
620 | ✗ | continue; | |
621 |
3/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
|
6 | for (j = 0; j < img->block_info[i].num_lines && idx < 2; j++) |
622 | 4 | b[idx++] = img->data[r++]; | |
623 | } | ||
624 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (!b[0] || !b[1]) |
625 | { | ||
626 | ✗ | fp_dbg ("NULL! %p %p", b[0], b[1]); | |
627 | ✗ | return 0; | |
628 | } | ||
629 |
2/2✓ Branch 0 taken 768 times.
✓ Branch 1 taken 2 times.
|
770 | for (i = 0; i < IMAGE_WIDTH; i++) |
630 | 768 | mean += (int) b[0][i] + (int) b[1][i]; | |
631 | |||
632 | 2 | mean /= IMAGE_WIDTH; | |
633 | |||
634 |
2/2✓ Branch 0 taken 768 times.
✓ Branch 1 taken 2 times.
|
770 | for (i = 0; i < IMAGE_WIDTH; i++) |
635 | { | ||
636 | 768 | int dev = (int) b[0][i] + (int) b[1][i] - mean; | |
637 | 768 | res += dev * dev; | |
638 | } | ||
639 | |||
640 | 2 | return res / IMAGE_WIDTH; | |
641 | } | ||
642 | |||
643 | static void | ||
644 | 10 | imaging_run_state (FpiSsm *ssm, FpDevice *_dev) | |
645 | { | ||
646 | 10 | FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); | |
647 | 10 | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (_dev); | |
648 | 10 | struct uru4k_image *img = self->img_data; | |
649 | 10 | FpImage *fpimg; | |
650 | 10 | uint32_t key; | |
651 | 10 | uint8_t flags, num_lines; | |
652 | 10 | int i, r, to, dev2; | |
653 | 10 | unsigned char buf[5]; | |
654 | |||
655 |
5/6✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
10 | switch (fpi_ssm_get_cur_state (ssm)) |
656 | { | ||
657 | 2 | case IMAGING_CAPTURE: | |
658 | 2 | self->img_lines_done = 0; | |
659 | 2 | self->img_block = 0; | |
660 | 2 | fpi_usb_transfer_submit (fpi_usb_transfer_ref (self->img_transfer), | |
661 | 0, | ||
662 | NULL, | ||
663 | image_transfer_cb, | ||
664 | NULL); | ||
665 | |||
666 | 2 | break; | |
667 | |||
668 | 2 | case IMAGING_SEND_INDEX: | |
669 | 2 | fp_dbg ("hw header lines %d", img->num_lines); | |
670 | |||
671 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (img->num_lines >= IMAGE_HEIGHT || |
672 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | self->img_data_actual_length < img->num_lines * IMAGE_WIDTH + 64) |
673 | { | ||
674 | ✗ | fp_err ("bad captured image (%d lines) or size mismatch %d < %d", | |
675 | img->num_lines, | ||
676 | self->img_data_actual_length, | ||
677 | img->num_lines * IMAGE_WIDTH + 64); | ||
678 | ✗ | fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE); | |
679 | ✗ | return; | |
680 | } | ||
681 | |||
682 | /* Detect whether image is encrypted (by checking how noisy it is) */ | ||
683 | 2 | dev2 = calc_dev2 (img); | |
684 | 2 | fp_dbg ("dev2: %d", dev2); | |
685 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (dev2 < ENC_THRESHOLD) |
686 | { | ||
687 | ✗ | fpi_ssm_jump_to_state (ssm, IMAGING_REPORT_IMAGE); | |
688 | ✗ | return; | |
689 | } | ||
690 | 2 | fp_info ("image seems to be encrypted"); | |
691 | |||
692 | 2 | buf[0] = img->key_number; | |
693 | 2 | buf[1] = self->img_enc_seed; | |
694 | 2 | buf[2] = self->img_enc_seed >> 8; | |
695 | 2 | buf[3] = self->img_enc_seed >> 16; | |
696 | 2 | buf[4] = self->img_enc_seed >> 24; | |
697 | 2 | sm_write_regs (ssm, dev, REG_SCRAMBLE_DATA_INDEX, 5, buf); | |
698 | 2 | break; | |
699 | |||
700 | 2 | case IMAGING_READ_KEY: | |
701 | 2 | sm_read_regs (ssm, dev, REG_SCRAMBLE_DATA_KEY, 4); | |
702 | 2 | break; | |
703 | |||
704 | 2 | case IMAGING_DECODE: | |
705 | 2 | key = self->last_reg_rd[0]; | |
706 | 2 | key |= self->last_reg_rd[1] << 8; | |
707 | 2 | key |= self->last_reg_rd[2] << 16; | |
708 | 2 | key |= self->last_reg_rd[3] << 24; | |
709 | 2 | key ^= self->img_enc_seed; | |
710 | |||
711 | 2 | fp_dbg ("encryption id %02x -> key %08x", img->key_number, key); | |
712 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | while (self->img_block < G_N_ELEMENTS (img->block_info) && |
713 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 2 times.
|
18 | self->img_lines_done < img->num_lines) |
714 | { | ||
715 | 16 | flags = img->block_info[self->img_block].flags; | |
716 | 16 | num_lines = img->block_info[self->img_block].num_lines; | |
717 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | if (num_lines == 0) |
718 | break; | ||
719 | |||
720 | 16 | fp_dbg ("%d %02x %d", self->img_block, flags, | |
721 | num_lines); | ||
722 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (flags & BLOCKF_CHANGE_KEY) |
723 | { | ||
724 | ✗ | fp_dbg ("changing encryption keys."); | |
725 | ✗ | img->block_info[self->img_block].flags &= ~BLOCKF_CHANGE_KEY; | |
726 | ✗ | img->key_number++; | |
727 | ✗ | self->img_enc_seed = g_rand_int_range (self->rand, 0, RAND_MAX); | |
728 | ✗ | fp_dbg ("New image encryption seed: %d", self->img_enc_seed); | |
729 | ✗ | fpi_ssm_jump_to_state (ssm, IMAGING_SEND_INDEX); | |
730 | ✗ | return; | |
731 | } | ||
732 |
2/3✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
16 | switch (flags & (BLOCKF_NO_KEY_UPDATE | BLOCKF_ENCRYPTED)) |
733 | { | ||
734 | 8 | case BLOCKF_ENCRYPTED: | |
735 | 8 | fp_dbg ("decoding %d lines", num_lines); | |
736 | 8 | key = do_decode (&img->data[self->img_lines_done][0], | |
737 | IMAGE_WIDTH * num_lines, key); | ||
738 | 8 | break; | |
739 | |||
740 | 8 | case 0: | |
741 | 8 | fp_dbg ("skipping %d lines", num_lines); | |
742 |
2/2✓ Branch 1 taken 3072 times.
✓ Branch 2 taken 8 times.
|
3088 | for (r = 0; r < IMAGE_WIDTH * num_lines; r++) |
743 | 3072 | key = update_key (key); | |
744 | break; | ||
745 | } | ||
746 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
|
16 | if ((flags & BLOCKF_NOT_PRESENT) == 0) |
747 | 14 | self->img_lines_done += num_lines; | |
748 | 16 | self->img_block++; | |
749 | } | ||
750 | 2 | fpi_ssm_next_state (ssm); | |
751 | 2 | break; | |
752 | |||
753 | 2 | case IMAGING_REPORT_IMAGE: | |
754 | 2 | fpimg = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT); | |
755 | |||
756 | 2 | to = r = 0; | |
757 |
3/4✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 2 times.
|
20 | for (i = 0; i < G_N_ELEMENTS (img->block_info) && r < img->num_lines; i++) |
758 | { | ||
759 | 16 | flags = img->block_info[i].flags; | |
760 | 16 | num_lines = img->block_info[i].num_lines; | |
761 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | if (num_lines == 0) |
762 | break; | ||
763 | 16 | memcpy (&fpimg->data[to], &img->data[r][0], | |
764 | 16 | num_lines * IMAGE_WIDTH); | |
765 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
|
16 | if (!(flags & BLOCKF_NOT_PRESENT)) |
766 | 14 | r += num_lines; | |
767 | 16 | to += num_lines * IMAGE_WIDTH; | |
768 | } | ||
769 | |||
770 | 2 | fpimg->flags = FPI_IMAGE_COLORS_INVERTED; | |
771 | /* NOTE: For some reason all but U4000B (or rather U4500?) flipped the | ||
772 | * image, we retain this behaviour here, but it is not clear whether it | ||
773 | * is correct. | ||
774 | * It may be that there are different models with the same USB ID that | ||
775 | * behave differently. | ||
776 | */ | ||
777 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (self->profile->image_not_flipped) |
778 | 1 | fpimg->flags |= FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED; | |
779 | 2 | fpi_image_device_image_captured (dev, fpimg); | |
780 | |||
781 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (self->activate_state == FPI_IMAGE_DEVICE_STATE_CAPTURE) |
782 | ✗ | fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE); | |
783 | else | ||
784 | 2 | fpi_ssm_mark_completed (ssm); | |
785 | break; | ||
786 | } | ||
787 | } | ||
788 | |||
789 | static void | ||
790 | 2 | imaging_complete (FpiSsm *ssm, FpDevice *dev, GError *error) | |
791 | { | ||
792 | 2 | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); | |
793 | |||
794 | |||
795 | /* Report error before exiting imaging loop - the error handler | ||
796 | * can request state change, which needs to be postponed to end of | ||
797 | * this function. */ | ||
798 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (error) |
799 | ✗ | fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error); | |
800 | |||
801 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | g_clear_pointer (&self->img_transfer, fpi_usb_transfer_unref); |
802 | |||
803 | 2 | g_free (self->img_data); | |
804 | 2 | self->img_data = NULL; | |
805 | 2 | self->img_data_actual_length = 0; | |
806 | |||
807 | 2 | execute_state_change (FP_IMAGE_DEVICE (dev)); | |
808 | 2 | } | |
809 | |||
810 | /***** INITIALIZATION *****/ | ||
811 | |||
812 | /* After closing an app and setting hwstat to 0x80, my ms keyboard gets in a | ||
813 | * confused state and returns hwstat 0x85. On next app run, we don't get the | ||
814 | * 56aa interrupt. This is the best way I've found to fix it: mess around | ||
815 | * with hwstat until it starts returning more recognisable values. This | ||
816 | * doesn't happen on my other devices: uru4000, uru4000b, ms fp rdr v2 | ||
817 | * | ||
818 | * The windows driver copes with this OK, but then again it uploads firmware | ||
819 | * right after reading the 0x85 hwstat, allowing some time to pass before it | ||
820 | * attempts to tweak hwstat again... | ||
821 | * | ||
822 | * This is implemented with a reboot power state machine. the ssm runs during | ||
823 | * initialization if bits 2 and 7 are set in hwstat. it masks off the 4 high | ||
824 | * hwstat bits then checks that bit 1 is set. if not, it pauses before reading | ||
825 | * hwstat again. machine completes when reading hwstat shows bit 1 is set, | ||
826 | * and fails after 100 tries. */ | ||
827 | |||
828 | enum rebootpwr_states { | ||
829 | REBOOTPWR_SET_HWSTAT = 0, | ||
830 | REBOOTPWR_GET_HWSTAT, | ||
831 | REBOOTPWR_CHECK_HWSTAT, | ||
832 | REBOOTPWR_PAUSE, | ||
833 | REBOOTPWR_NUM_STATES, | ||
834 | }; | ||
835 | |||
836 | static void | ||
837 | ✗ | rebootpwr_run_state (FpiSsm *ssm, FpDevice *_dev) | |
838 | { | ||
839 | ✗ | FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); | |
840 | ✗ | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (_dev); | |
841 | |||
842 | ✗ | switch (fpi_ssm_get_cur_state (ssm)) | |
843 | { | ||
844 | ✗ | case REBOOTPWR_SET_HWSTAT: | |
845 | ✗ | self->rebootpwr_ctr = 100; | |
846 | ✗ | sm_set_hwstat (ssm, dev, self->last_hwstat & 0xf); | |
847 | ✗ | break; | |
848 | |||
849 | case REBOOTPWR_GET_HWSTAT: | ||
850 | ✗ | sm_read_reg (ssm, dev, REG_HWSTAT); | |
851 | ✗ | break; | |
852 | |||
853 | ✗ | case REBOOTPWR_CHECK_HWSTAT: | |
854 | ✗ | self->last_hwstat = self->last_reg_rd[0]; | |
855 | ✗ | if (self->last_hwstat & 0x1) | |
856 | ✗ | fpi_ssm_mark_completed (ssm); | |
857 | else | ||
858 | ✗ | fpi_ssm_next_state (ssm); | |
859 | break; | ||
860 | |||
861 | ✗ | case REBOOTPWR_PAUSE: | |
862 | ✗ | if (!--self->rebootpwr_ctr) | |
863 | { | ||
864 | ✗ | fp_err ("could not reboot device power"); | |
865 | ✗ | fpi_ssm_mark_failed (ssm, | |
866 | ✗ | fpi_device_error_new_msg (FP_DEVICE_ERROR, | |
867 | "Could not reboot device")); | ||
868 | } | ||
869 | else | ||
870 | { | ||
871 | ✗ | fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT); | |
872 | } | ||
873 | break; | ||
874 | } | ||
875 | ✗ | } | |
876 | |||
877 | /* After messing with the device firmware in its low-power state, we have to | ||
878 | * power it back up and wait for interrupt notification. It's not quite as easy | ||
879 | * as that: the combination of both modifying firmware *and* doing C-R auth on | ||
880 | * my ms fp v2 device causes us not to get the 56aa interrupt and | ||
881 | * for the hwstat write not to take effect. We have to loop a few times, | ||
882 | * authenticating each time, until the device wakes up. | ||
883 | * | ||
884 | * This is implemented as the powerup state machine below. Pseudo-code: | ||
885 | |||
886 | status = get_hwstat(); | ||
887 | for (i = 0; i < 100; i++) { | ||
888 | set_hwstat(status & 0xf); | ||
889 | if ((get_hwstat() & 0x80) == 0) | ||
890 | break; | ||
891 | |||
892 | usleep(10000); | ||
893 | if (need_auth_cr) | ||
894 | auth_cr(); | ||
895 | } | ||
896 | |||
897 | if (tmp & 0x80) | ||
898 | error("could not power up device"); | ||
899 | |||
900 | */ | ||
901 | |||
902 | enum powerup_states { | ||
903 | POWERUP_INIT = 0, | ||
904 | POWERUP_SET_HWSTAT, | ||
905 | POWERUP_GET_HWSTAT, | ||
906 | POWERUP_CHECK_HWSTAT, | ||
907 | POWERUP_PAUSE, | ||
908 | POWERUP_CHALLENGE_RESPONSE, | ||
909 | POWERUP_CHALLENGE_RESPONSE_SUCCESS, | ||
910 | POWERUP_NUM_STATES, | ||
911 | }; | ||
912 | |||
913 | static void | ||
914 | 14 | powerup_run_state (FpiSsm *ssm, FpDevice *_dev) | |
915 | { | ||
916 | 14 | FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); | |
917 | 14 | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (_dev); | |
918 | |||
919 |
7/8✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
14 | switch (fpi_ssm_get_cur_state (ssm)) |
920 | { | ||
921 | 2 | case POWERUP_INIT: | |
922 | 2 | self->powerup_ctr = 100; | |
923 | 2 | self->powerup_hwstat = self->last_hwstat & 0xf; | |
924 | 2 | fpi_ssm_next_state (ssm); | |
925 | 2 | break; | |
926 | |||
927 | 3 | case POWERUP_SET_HWSTAT: | |
928 | 3 | sm_set_hwstat (ssm, dev, self->powerup_hwstat); | |
929 | 3 | break; | |
930 | |||
931 | case POWERUP_GET_HWSTAT: | ||
932 | 3 | sm_read_reg (ssm, dev, REG_HWSTAT); | |
933 | 3 | break; | |
934 | |||
935 | 3 | case POWERUP_CHECK_HWSTAT: | |
936 | 3 | self->last_hwstat = self->last_reg_rd[0]; | |
937 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | if ((self->last_reg_rd[0] & 0x80) == 0) |
938 | 2 | fpi_ssm_mark_completed (ssm); | |
939 | else | ||
940 | 1 | fpi_ssm_next_state (ssm); | |
941 | break; | ||
942 | |||
943 | 1 | case POWERUP_PAUSE: | |
944 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!--self->powerup_ctr) |
945 | { | ||
946 | ✗ | fp_err ("could not power device up"); | |
947 | ✗ | fpi_ssm_mark_failed (ssm, | |
948 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
949 | "could not power device up")); | ||
950 | } | ||
951 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | else if (!self->profile->auth_cr) |
952 | { | ||
953 | ✗ | fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10); | |
954 | } | ||
955 | else | ||
956 | { | ||
957 | 1 | fpi_ssm_next_state_delayed (ssm, 10); | |
958 | } | ||
959 | break; | ||
960 | |||
961 | 1 | case POWERUP_CHALLENGE_RESPONSE: | |
962 | 1 | sm_do_challenge_response (ssm, dev); | |
963 | 1 | break; | |
964 | |||
965 | 1 | case POWERUP_CHALLENGE_RESPONSE_SUCCESS: | |
966 | 1 | fpi_ssm_jump_to_state (ssm, POWERUP_SET_HWSTAT); | |
967 | 1 | break; | |
968 | } | ||
969 | 14 | } | |
970 | |||
971 | /* | ||
972 | * This is the main initialization state machine. As pseudo-code: | ||
973 | |||
974 | status = get_hwstat(); | ||
975 | |||
976 | // correct device power state | ||
977 | if ((status & 0x84) == 0x84) | ||
978 | run_reboot_sm(); | ||
979 | |||
980 | // power device down | ||
981 | if ((status & 0x80) == 0) | ||
982 | set_hwstat(status | 0x80); | ||
983 | |||
984 | // power device up | ||
985 | run_powerup_sm(); | ||
986 | await_irq(IRQDATA_SCANPWR_ON); | ||
987 | */ | ||
988 | |||
989 | enum init_states { | ||
990 | INIT_GET_HWSTAT = 0, | ||
991 | INIT_CHECK_HWSTAT_REBOOT, | ||
992 | INIT_REBOOT_POWER, | ||
993 | INIT_CHECK_HWSTAT_POWERDOWN, | ||
994 | INIT_POWERUP, | ||
995 | INIT_AWAIT_SCAN_POWER, | ||
996 | INIT_DONE, | ||
997 | INIT_GET_VERSION, | ||
998 | INIT_REPORT_VERSION, | ||
999 | INIT_NUM_STATES, | ||
1000 | }; | ||
1001 | |||
1002 | static void | ||
1003 | 2 | init_scanpwr_irq_cb (FpImageDevice *dev, GError *error, | |
1004 | uint16_t type, void *user_data) | ||
1005 | { | ||
1006 | 2 | FpiSsm *ssm = user_data; | |
1007 | 2 | FpiDeviceUru4000 *urudev = FPI_DEVICE_URU4000 (dev); | |
1008 | |||
1009 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (error) |
1010 | { | ||
1011 | ✗ | fpi_ssm_mark_failed (ssm, error); | |
1012 | } | ||
1013 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | else if (type != IRQDATA_SCANPWR_ON) |
1014 | { | ||
1015 | ✗ | fp_dbg ("ignoring interrupt"); | |
1016 | } | ||
1017 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
|
2 | else if (fpi_ssm_get_cur_state (ssm) != INIT_AWAIT_SCAN_POWER) |
1018 | { | ||
1019 | 1 | fp_dbg ("early scanpwr interrupt"); | |
1020 | 1 | urudev->scanpwr_irq_timeouts = -1; | |
1021 | } | ||
1022 | else | ||
1023 | { | ||
1024 | 1 | fp_dbg ("late scanpwr interrupt"); | |
1025 | 1 | fpi_ssm_next_state (ssm); | |
1026 | } | ||
1027 | 2 | } | |
1028 | |||
1029 | static void | ||
1030 | ✗ | init_scanpwr_timeout (FpDevice *dev, | |
1031 | void *user_data) | ||
1032 | { | ||
1033 | ✗ | FpiSsm *ssm = user_data; | |
1034 | ✗ | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); | |
1035 | |||
1036 | ✗ | fp_warn ("powerup timed out"); | |
1037 | ✗ | self->irq_cb = NULL; | |
1038 | ✗ | self->scanpwr_irq_timeout = NULL; | |
1039 | |||
1040 | ✗ | if (++self->scanpwr_irq_timeouts >= 3) | |
1041 | { | ||
1042 | ✗ | fp_err ("powerup timed out 3 times, giving up"); | |
1043 | ✗ | fpi_ssm_mark_failed (ssm, | |
1044 | g_error_new_literal (G_USB_DEVICE_ERROR, | ||
1045 | G_USB_DEVICE_ERROR_TIMED_OUT, | ||
1046 | "Powerup timed out 3 times, giving up")); | ||
1047 | } | ||
1048 | else | ||
1049 | { | ||
1050 | ✗ | fpi_ssm_jump_to_state (ssm, INIT_GET_HWSTAT); | |
1051 | } | ||
1052 | ✗ | } | |
1053 | |||
1054 | static void | ||
1055 | 16 | init_run_state (FpiSsm *ssm, FpDevice *_dev) | |
1056 | { | ||
1057 | 16 | FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); | |
1058 | 16 | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (_dev); | |
1059 | |||
1060 |
8/10✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
|
16 | switch (fpi_ssm_get_cur_state (ssm)) |
1061 | { | ||
1062 | case INIT_GET_HWSTAT: | ||
1063 | 2 | sm_read_reg (ssm, dev, REG_HWSTAT); | |
1064 | 2 | break; | |
1065 | |||
1066 | 2 | case INIT_CHECK_HWSTAT_REBOOT: | |
1067 | 2 | self->last_hwstat = self->last_reg_rd[0]; | |
1068 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if ((self->last_hwstat & 0x84) == 0x84) |
1069 | ✗ | fpi_ssm_next_state (ssm); | |
1070 | else | ||
1071 | 2 | fpi_ssm_jump_to_state (ssm, INIT_CHECK_HWSTAT_POWERDOWN); | |
1072 | break; | ||
1073 | |||
1074 | ✗ | case INIT_REBOOT_POWER:; | |
1075 | ✗ | FpiSsm *rebootsm = fpi_ssm_new (FP_DEVICE (dev), | |
1076 | rebootpwr_run_state, | ||
1077 | REBOOTPWR_NUM_STATES); | ||
1078 | ✗ | fpi_ssm_start_subsm (ssm, rebootsm); | |
1079 | ✗ | break; | |
1080 | |||
1081 | 2 | case INIT_CHECK_HWSTAT_POWERDOWN: | |
1082 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if ((self->last_hwstat & 0x80) == 0) |
1083 | 2 | sm_set_hwstat (ssm, dev, self->last_hwstat | 0x80); | |
1084 | else | ||
1085 | ✗ | fpi_ssm_next_state (ssm); | |
1086 | break; | ||
1087 | |||
1088 | 2 | case INIT_POWERUP: | |
1089 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!IRQ_HANDLER_IS_RUNNING (self)) |
1090 | { | ||
1091 | ✗ | fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | |
1092 | "IRQ handler should be running but is not")); | ||
1093 | ✗ | return; | |
1094 | } | ||
1095 | 2 | self->irq_cb_data = ssm; | |
1096 | 2 | self->irq_cb = init_scanpwr_irq_cb; | |
1097 | |||
1098 | 2 | FpiSsm *powerupsm = fpi_ssm_new (FP_DEVICE (dev), | |
1099 | powerup_run_state, | ||
1100 | POWERUP_NUM_STATES); | ||
1101 | 2 | fpi_ssm_start_subsm (ssm, powerupsm); | |
1102 | 2 | break; | |
1103 | |||
1104 | 2 | case INIT_AWAIT_SCAN_POWER: | |
1105 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (self->scanpwr_irq_timeouts < 0) |
1106 | { | ||
1107 | 1 | fpi_ssm_next_state (ssm); | |
1108 | 1 | break; | |
1109 | } | ||
1110 | |||
1111 | /* sometimes the 56aa interrupt that we are waiting for never arrives, | ||
1112 | * so we include this timeout loop to retry the whole process 3 times | ||
1113 | * if we don't get an irq any time soon. */ | ||
1114 | 1 | self->scanpwr_irq_timeout = fpi_device_add_timeout (_dev, | |
1115 | 300, | ||
1116 | init_scanpwr_timeout, | ||
1117 | ssm, NULL); | ||
1118 | 1 | break; | |
1119 | |||
1120 | 2 | case INIT_DONE: | |
1121 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (self->scanpwr_irq_timeout) |
1122 | { | ||
1123 | 1 | g_source_destroy (self->scanpwr_irq_timeout); | |
1124 | 1 | self->scanpwr_irq_timeout = NULL; | |
1125 | } | ||
1126 | 2 | self->irq_cb_data = NULL; | |
1127 | 2 | self->irq_cb = NULL; | |
1128 | 2 | fpi_ssm_next_state (ssm); | |
1129 | 2 | break; | |
1130 | |||
1131 | 2 | case INIT_GET_VERSION: | |
1132 | 2 | sm_read_regs (ssm, dev, REG_DEVICE_INFO, 16); | |
1133 | 2 | break; | |
1134 | |||
1135 | 2 | case INIT_REPORT_VERSION: | |
1136 | /* Likely hardware revision, and firmware version. | ||
1137 | * Not sure which is which. */ | ||
1138 | 2 | fp_info ("Versions %02x%02x and %02x%02x", | |
1139 | self->last_reg_rd[10], self->last_reg_rd[11], | ||
1140 | self->last_reg_rd[4], self->last_reg_rd[5]); | ||
1141 | 2 | fpi_ssm_mark_completed (ssm); | |
1142 | 2 | break; | |
1143 | } | ||
1144 | } | ||
1145 | |||
1146 | static void | ||
1147 | 2 | activate_initsm_complete (FpiSsm *ssm, FpDevice *dev, GError *error) | |
1148 | { | ||
1149 | 2 | fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error); | |
1150 | 2 | } | |
1151 | |||
1152 | static void | ||
1153 | 2 | dev_activate (FpImageDevice *dev) | |
1154 | { | ||
1155 | 2 | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); | |
1156 | 2 | FpiSsm *ssm; | |
1157 | |||
1158 | 2 | start_irq_handler (dev); | |
1159 | |||
1160 | 2 | self->scanpwr_irq_timeouts = 0; | |
1161 | 2 | ssm = fpi_ssm_new (FP_DEVICE (dev), init_run_state, INIT_NUM_STATES); | |
1162 | 2 | fpi_ssm_start (ssm, activate_initsm_complete); | |
1163 | 2 | } | |
1164 | |||
1165 | /***** DEINITIALIZATION *****/ | ||
1166 | |||
1167 | static void | ||
1168 | 2 | deactivate_irqs_stopped (FpImageDevice *dev) | |
1169 | { | ||
1170 | 2 | fpi_image_device_deactivate_complete (dev, NULL); | |
1171 | 2 | } | |
1172 | |||
1173 | static void | ||
1174 | 2 | deactivate_write_reg_cb (FpiUsbTransfer *transfer, FpDevice *dev, | |
1175 | gpointer user_data, GError *error) | ||
1176 | { | ||
1177 | 2 | stop_irq_handler (FP_IMAGE_DEVICE (dev), deactivate_irqs_stopped); | |
1178 | 2 | } | |
1179 | |||
1180 | static void | ||
1181 | 2 | dev_deactivate (FpImageDevice *dev) | |
1182 | { | ||
1183 | /* This is started/handled by execute_state_change in order to delay the | ||
1184 | * action until after the image transfer has completed. | ||
1185 | * We just need to override the function so that the complete handler is | ||
1186 | * not called automatically. */ | ||
1187 | 2 | } | |
1188 | |||
1189 | static void | ||
1190 | 16 | execute_state_change (FpImageDevice *dev) | |
1191 | { | ||
1192 | 16 | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); | |
1193 | 16 | FpiSsm *ssm; | |
1194 | |||
1195 |
5/5✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 8 times.
|
16 | switch (self->activate_state) |
1196 | { | ||
1197 | 2 | case FPI_IMAGE_DEVICE_STATE_DEACTIVATING: | |
1198 | 2 | fp_dbg ("deactivating"); | |
1199 | 2 | self->irq_cb = NULL; | |
1200 | 2 | self->irq_cb_data = NULL; | |
1201 | 2 | write_reg (dev, REG_MODE, MODE_OFF, | |
1202 | deactivate_write_reg_cb, NULL); | ||
1203 | 2 | break; | |
1204 | |||
1205 | 2 | case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: | |
1206 | 2 | fp_dbg ("wait finger on"); | |
1207 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!IRQ_HANDLER_IS_RUNNING (self)) |
1208 | { | ||
1209 | ✗ | fpi_image_device_session_error (dev, | |
1210 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
1211 | "IRQ handler should be running but is not")); | ||
1212 | ✗ | return; | |
1213 | } | ||
1214 | 2 | self->irq_cb = finger_presence_irq_cb; | |
1215 | 2 | write_reg (dev, REG_MODE, MODE_AWAIT_FINGER_ON, | |
1216 | change_state_write_reg_cb, NULL); | ||
1217 | 2 | break; | |
1218 | |||
1219 | 2 | case FPI_IMAGE_DEVICE_STATE_CAPTURE: | |
1220 | 2 | fp_dbg ("starting capture"); | |
1221 | 2 | self->irq_cb = NULL; | |
1222 | |||
1223 | 2 | ssm = fpi_ssm_new (FP_DEVICE (dev), imaging_run_state, | |
1224 | IMAGING_NUM_STATES); | ||
1225 | 2 | self->img_enc_seed = g_rand_int_range (self->rand, 0, RAND_MAX); | |
1226 | 2 | fp_dbg ("Image encryption seed: %d", self->img_enc_seed); | |
1227 | 2 | self->img_transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); | |
1228 | 2 | self->img_transfer->ssm = ssm; | |
1229 | 2 | self->img_transfer->short_is_error = FALSE; | |
1230 | 2 | fpi_usb_transfer_fill_bulk (self->img_transfer, | |
1231 | EP_DATA, | ||
1232 | sizeof (struct uru4k_image)); | ||
1233 | |||
1234 | 2 | fpi_ssm_start (ssm, imaging_complete); | |
1235 | |||
1236 | 2 | write_reg (dev, REG_MODE, MODE_CAPTURE, | |
1237 | change_state_write_reg_cb, NULL); | ||
1238 | 2 | break; | |
1239 | |||
1240 | 2 | case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: | |
1241 | 2 | fp_dbg ("await finger off"); | |
1242 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!IRQ_HANDLER_IS_RUNNING (self)) |
1243 | { | ||
1244 | ✗ | fpi_image_device_session_error (dev, | |
1245 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
1246 | "IRQ handler should be running but is not")); | ||
1247 | ✗ | return; | |
1248 | } | ||
1249 | 2 | self->irq_cb = finger_presence_irq_cb; | |
1250 | 2 | write_reg (dev, REG_MODE, MODE_AWAIT_FINGER_OFF, | |
1251 | change_state_write_reg_cb, NULL); | ||
1252 | 2 | break; | |
1253 | |||
1254 | /* Ignored states */ | ||
1255 | case FPI_IMAGE_DEVICE_STATE_IDLE: | ||
1256 | case FPI_IMAGE_DEVICE_STATE_ACTIVATING: | ||
1257 | case FPI_IMAGE_DEVICE_STATE_INACTIVE: | ||
1258 | break; | ||
1259 | } | ||
1260 | } | ||
1261 | |||
1262 | /***** LIBRARY STUFF *****/ | ||
1263 | |||
1264 | static void | ||
1265 | 2 | dev_init (FpImageDevice *dev) | |
1266 | { | ||
1267 | 2 | GError *error = NULL; | |
1268 | 2 | FpiDeviceUru4000 *self; | |
1269 | |||
1270 | 2 | g_autoptr(GPtrArray) interfaces = NULL; | |
1271 | 2 | GUsbInterface *iface = NULL; | |
1272 | 2 | guint64 driver_data; | |
1273 | 2 | SECStatus rv; | |
1274 | 2 | SECItem item; | |
1275 | 2 | int i; | |
1276 | |||
1277 | 2 | interfaces = g_usb_device_get_interfaces (fpi_device_get_usb_device (FP_DEVICE (dev)), &error); | |
1278 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (error) |
1279 | { | ||
1280 | ✗ | fpi_image_device_open_complete (dev, error); | |
1281 | ✗ | return; | |
1282 | } | ||
1283 | |||
1284 | /* Find fingerprint interface; TODO: Move this into probe() */ | ||
1285 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | for (i = 0; i < interfaces->len; i++) |
1286 | { | ||
1287 | 2 | GUsbInterface *cur_iface = g_ptr_array_index (interfaces, i); | |
1288 | |||
1289 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
4 | if (g_usb_interface_get_class (cur_iface) == 255 && |
1290 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
4 | g_usb_interface_get_subclass (cur_iface) == 255 && |
1291 | 2 | g_usb_interface_get_protocol (cur_iface) == 255) | |
1292 | { | ||
1293 | iface = cur_iface; | ||
1294 | break; | ||
1295 | } | ||
1296 | } | ||
1297 | |||
1298 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (iface == NULL) |
1299 | { | ||
1300 | ✗ | fp_err ("could not find interface"); | |
1301 | ✗ | fpi_image_device_open_complete (dev, | |
1302 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
1303 | "Could not find interface")); | ||
1304 | ✗ | return; | |
1305 | } | ||
1306 | |||
1307 | /* TODO: Find/check endpoints; does not seem easily possible with GUsb unfortunately! */ | ||
1308 | #if 0 | ||
1309 | if (iface_desc->bNumEndpoints != 2) | ||
1310 | { | ||
1311 | fp_err ("found %d endpoints!?", iface_desc->bNumEndpoints); | ||
1312 | r = -ENODEV; | ||
1313 | goto out; | ||
1314 | } | ||
1315 | |||
1316 | ep = &iface_desc->endpoint[0]; | ||
1317 | if (ep->bEndpointAddress != EP_INTR || | ||
1318 | (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) != | ||
1319 | LIBUSB_TRANSFER_TYPE_INTERRUPT) | ||
1320 | { | ||
1321 | fp_err ("unrecognised interrupt endpoint"); | ||
1322 | r = -ENODEV; | ||
1323 | goto out; | ||
1324 | } | ||
1325 | |||
1326 | ep = &iface_desc->endpoint[1]; | ||
1327 | if (ep->bEndpointAddress != EP_DATA || | ||
1328 | (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) != | ||
1329 | LIBUSB_TRANSFER_TYPE_BULK) | ||
1330 | { | ||
1331 | fp_err ("unrecognised bulk endpoint"); | ||
1332 | r = -ENODEV; | ||
1333 | goto out; | ||
1334 | } | ||
1335 | #endif | ||
1336 | |||
1337 | /* Device looks like a supported reader */ | ||
1338 | |||
1339 |
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)), |
1340 | 2 | g_usb_interface_get_number (iface), 0, &error)) | |
1341 | { | ||
1342 | ✗ | fpi_image_device_open_complete (dev, error); | |
1343 | ✗ | return; | |
1344 | } | ||
1345 | |||
1346 | /* Disable loading p11-kit's user configuration */ | ||
1347 | 2 | g_setenv ("P11_KIT_NO_USER_CONFIG", "1", TRUE); | |
1348 | |||
1349 | /* Initialise NSS early */ | ||
1350 | 2 | rv = NSS_NoDB_Init ("."); | |
1351 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (rv != SECSuccess) |
1352 | { | ||
1353 | ✗ | fp_err ("could not initialise NSS"); | |
1354 | ✗ | fpi_image_device_open_complete (dev, | |
1355 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
1356 | "Could not initialise NSS")); | ||
1357 | ✗ | return; | |
1358 | } | ||
1359 | |||
1360 | 2 | self = FPI_DEVICE_URU4000 (dev); | |
1361 | |||
1362 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | g_clear_pointer (&self->rand, g_rand_free); |
1363 | 2 | self->rand = g_rand_new (); | |
1364 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0) |
1365 | 2 | g_rand_set_seed (self->rand, 0xFACADE); | |
1366 | |||
1367 | 2 | driver_data = fpi_device_get_driver_data (FP_DEVICE (dev)); | |
1368 | 2 | self->profile = &uru4k_dev_info[driver_data]; | |
1369 | 2 | self->interface = g_usb_interface_get_number (iface); | |
1370 | |||
1371 | /* Set up encryption */ | ||
1372 | 2 | self->cipher = CKM_AES_ECB; | |
1373 | 2 | self->slot = PK11_GetBestSlot (self->cipher, NULL); | |
1374 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (self->slot == NULL) |
1375 | { | ||
1376 | ✗ | fp_err ("could not get encryption slot"); | |
1377 | ✗ | fpi_image_device_open_complete (dev, | |
1378 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
1379 | "Could not get encryption slot")); | ||
1380 | ✗ | return; | |
1381 | } | ||
1382 | 2 | item.type = siBuffer; | |
1383 | 2 | item.data = (unsigned char *) crkey; | |
1384 | 2 | item.len = sizeof (crkey); | |
1385 | 2 | self->symkey = PK11_ImportSymKey (self->slot, | |
1386 | self->cipher, | ||
1387 | PK11_OriginUnwrap, | ||
1388 | CKA_ENCRYPT, | ||
1389 | &item, NULL); | ||
1390 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (self->symkey == NULL) |
1391 | { | ||
1392 | ✗ | fp_err ("failed to import key into NSS"); | |
1393 | ✗ | PK11_FreeSlot (self->slot); | |
1394 | ✗ | self->slot = NULL; | |
1395 | ✗ | fpi_image_device_open_complete (dev, | |
1396 | fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, | ||
1397 | "Failed to import key into NSS")); | ||
1398 | ✗ | return; | |
1399 | } | ||
1400 | 2 | self->param = PK11_ParamFromIV (self->cipher, NULL); | |
1401 | |||
1402 | 2 | fpi_image_device_open_complete (dev, NULL); | |
1403 | } | ||
1404 | |||
1405 | static void | ||
1406 | 2 | dev_deinit (FpImageDevice *dev) | |
1407 | { | ||
1408 | 2 | GError *error = NULL; | |
1409 | 2 | FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); | |
1410 | |||
1411 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (self->symkey) |
1412 | 2 | PK11_FreeSymKey (self->symkey); | |
1413 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (self->param) |
1414 | 2 | SECITEM_FreeItem (self->param, PR_TRUE); | |
1415 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (self->slot) |
1416 | 2 | PK11_FreeSlot (self->slot); | |
1417 | |||
1418 | 2 | NSS_Shutdown (); | |
1419 | |||
1420 | 2 | g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), | |
1421 | 2 | self->interface, 0, &error); | |
1422 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | g_clear_pointer (&self->rand, g_rand_free); |
1423 | 2 | fpi_image_device_close_complete (dev, error); | |
1424 | 2 | } | |
1425 | |||
1426 | static const FpIdEntry id_table[] = { | ||
1427 | /* ms kbd with fp rdr */ | ||
1428 | { .vid = 0x045e, .pid = 0x00bb, .driver_data = MS_KBD }, | ||
1429 | |||
1430 | /* ms intellimouse with fp rdr */ | ||
1431 | { .vid = 0x045e, .pid = 0x00bc, .driver_data = MS_INTELLIMOUSE }, | ||
1432 | |||
1433 | /* ms fp rdr (standalone) */ | ||
1434 | { .vid = 0x045e, .pid = 0x00bd, .driver_data = MS_STANDALONE }, | ||
1435 | |||
1436 | /* ms fp rdr (standalone) v2 */ | ||
1437 | { .vid = 0x045e, .pid = 0x00ca, .driver_data = MS_STANDALONE_V2 }, | ||
1438 | |||
1439 | /* dp uru4000 (standalone) */ | ||
1440 | { .vid = 0x05ba, .pid = 0x0007, .driver_data = DP_URU4000 }, | ||
1441 | |||
1442 | /* dp uru4000 (keyboard) */ | ||
1443 | { .vid = 0x05ba, .pid = 0x0008, .driver_data = DP_URU4000 }, | ||
1444 | |||
1445 | /* dp uru4000b (standalone) */ | ||
1446 | { .vid = 0x05ba, .pid = 0x000a, .driver_data = DP_URU4000B }, | ||
1447 | |||
1448 | /* terminating entry */ | ||
1449 | { .vid = 0, .pid = 0, .driver_data = 0 }, | ||
1450 | }; | ||
1451 | |||
1452 | static void | ||
1453 | 2 | fpi_device_uru4000_init (FpiDeviceUru4000 *self) | |
1454 | { | ||
1455 | 2 | } | |
1456 | |||
1457 | static void | ||
1458 | 120 | fpi_device_uru4000_class_init (FpiDeviceUru4000Class *klass) | |
1459 | { | ||
1460 | 120 | FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); | |
1461 | 120 | FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); | |
1462 | |||
1463 | 120 | dev_class->id = "uru4000"; | |
1464 | 120 | dev_class->full_name = "Digital Persona U.are.U 4000/4000B/4500"; | |
1465 | 120 | dev_class->type = FP_DEVICE_TYPE_USB; | |
1466 | 120 | dev_class->id_table = id_table; | |
1467 | 120 | dev_class->scan_type = FP_SCAN_TYPE_PRESS; | |
1468 | |||
1469 | 120 | img_class->img_open = dev_init; | |
1470 | 120 | img_class->img_close = dev_deinit; | |
1471 | 120 | img_class->activate = dev_activate; | |
1472 | 120 | img_class->deactivate = dev_deactivate; | |
1473 | 120 | img_class->change_state = dev_change_state; | |
1474 | |||
1475 | 120 | img_class->img_width = IMAGE_WIDTH; | |
1476 | 120 | img_class->img_height = IMAGE_HEIGHT; | |
1477 | } | ||
1478 |