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