Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * AuthenTec AES2501 driver for libfprint | ||
3 | * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org> | ||
4 | * Copyright (C) 2007 Cyrille Bagard | ||
5 | * Copyright (C) 2007-2008, 2012 Vasily Khoruzhick <anarsoul@gmail.com> | ||
6 | * | ||
7 | * Based on code from http://home.gna.org/aes2501, relicensed with permission | ||
8 | * | ||
9 | * This library is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU Lesser General Public | ||
11 | * License as published by the Free Software Foundation; either | ||
12 | * version 2.1 of the License, or (at your option) any later version. | ||
13 | * | ||
14 | * This library is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * Lesser General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU Lesser General Public | ||
20 | * License along with this library; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | */ | ||
23 | |||
24 | #define FP_COMPONENT "aes2501" | ||
25 | |||
26 | #include "drivers_api.h" | ||
27 | #include "aeslib.h" | ||
28 | #include "aes2501.h" | ||
29 | |||
30 | static void start_capture (FpImageDevice *dev); | ||
31 | static void complete_deactivation (FpImageDevice *dev); | ||
32 | |||
33 | /* FIXME these need checking */ | ||
34 | #define EP_IN (1 | FPI_USB_ENDPOINT_IN) | ||
35 | #define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) | ||
36 | |||
37 | #define BULK_TIMEOUT 4000 | ||
38 | |||
39 | #define FINGER_DETECTION_LEN 20 | ||
40 | #define READ_REGS_LEN 126 | ||
41 | #define READ_REGS_RESP_LEN 159 | ||
42 | #define STRIP_CAPTURE_LEN 1705 | ||
43 | |||
44 | /* | ||
45 | * The AES2501 is an imaging device using a swipe-type sensor. It samples | ||
46 | * the finger at preprogrammed intervals, sending a 192x16 frame to the | ||
47 | * computer. | ||
48 | * Unless the user is scanning their finger unreasonably fast, the frames | ||
49 | * *will* overlap. The implementation below detects this overlap and produces | ||
50 | * a contiguous image as the end result. | ||
51 | * The fact that the user determines the length of the swipe (and hence the | ||
52 | * number of useful frames) and also the fact that overlap varies means that | ||
53 | * images returned from this driver vary in height. | ||
54 | */ | ||
55 | |||
56 | #define FRAME_WIDTH 192 | ||
57 | #define FRAME_HEIGHT 16 | ||
58 | #define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT) | ||
59 | #define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2)) | ||
60 | /* maximum number of frames to read during a scan */ | ||
61 | /* FIXME reduce substantially */ | ||
62 | #define MAX_FRAMES 150 | ||
63 | |||
64 | /****** GENERAL FUNCTIONS ******/ | ||
65 | |||
66 | struct _FpiDeviceAes2501 | ||
67 | { | ||
68 | FpImageDevice parent; | ||
69 | |||
70 | guint8 read_regs_retry_count; | ||
71 | GSList *strips; | ||
72 | size_t strips_len; | ||
73 | gboolean deactivating; | ||
74 | int no_finger_cnt; | ||
75 | }; | ||
76 | G_DECLARE_FINAL_TYPE (FpiDeviceAes2501, fpi_device_aes2501, FPI, DEVICE_AES2501, | ||
77 | FpImageDevice); | ||
78 |
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 (FpiDeviceAes2501, fpi_device_aes2501, FP_TYPE_IMAGE_DEVICE); |
79 | |||
80 | static struct fpi_frame_asmbl_ctx assembling_ctx = { | ||
81 | .frame_width = FRAME_WIDTH, | ||
82 | .frame_height = FRAME_HEIGHT, | ||
83 | .image_width = IMAGE_WIDTH, | ||
84 | .get_pixel = aes_get_pixel, | ||
85 | }; | ||
86 | |||
87 | typedef void (*aes2501_read_regs_cb)(FpImageDevice *dev, | ||
88 | GError *error, | ||
89 | unsigned char *regs, | ||
90 | void *user_data); | ||
91 | |||
92 | struct aes2501_read_regs | ||
93 | { | ||
94 | FpImageDevice *dev; | ||
95 | aes2501_read_regs_cb callback; | ||
96 | struct aes_regwrite *regwrite; | ||
97 | void *user_data; | ||
98 | }; | ||
99 | |||
100 | static void | ||
101 | 1 | read_regs_data_cb (FpiUsbTransfer *transfer, FpDevice *dev, | |
102 | gpointer user_data, GError *error) | ||
103 | { | ||
104 | 1 | struct aes2501_read_regs *rdata = user_data; | |
105 | |||
106 | 1 | rdata->callback (rdata->dev, error, transfer->buffer, rdata->user_data); | |
107 | 1 | g_free (rdata); | |
108 | 1 | } | |
109 | |||
110 | static void | ||
111 | 1 | read_regs_rq_cb (FpImageDevice *dev, GError *error, void *user_data) | |
112 | { | ||
113 | 1 | struct aes2501_read_regs *rdata = user_data; | |
114 | 1 | FpiUsbTransfer *transfer; | |
115 | |||
116 | 1 | g_free (rdata->regwrite); | |
117 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
118 | { | ||
119 | ✗ | rdata->callback (dev, error, NULL, rdata->user_data); | |
120 | ✗ | g_free (rdata); | |
121 | ✗ | return; | |
122 | } | ||
123 | |||
124 | 1 | transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); | |
125 | 1 | transfer->short_is_error = TRUE; | |
126 | 1 | fpi_usb_transfer_fill_bulk (transfer, EP_IN, READ_REGS_LEN); | |
127 | 1 | fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, | |
128 | read_regs_data_cb, rdata); | ||
129 | } | ||
130 | |||
131 | static void | ||
132 | 1 | read_regs (FpImageDevice *dev, aes2501_read_regs_cb callback, | |
133 | void *user_data) | ||
134 | { | ||
135 | /* FIXME: regwrite is dynamic because of asynchronity. is this really | ||
136 | * required? */ | ||
137 | 1 | struct aes_regwrite *regwrite = g_malloc (sizeof (*regwrite)); | |
138 | 1 | struct aes2501_read_regs *rdata = g_malloc (sizeof (*rdata)); | |
139 | |||
140 | 1 | G_DEBUG_HERE (); | |
141 | 1 | regwrite->reg = AES2501_REG_CTRL2; | |
142 | 1 | regwrite->value = AES2501_CTRL2_READ_REGS; | |
143 | 1 | rdata->dev = dev; | |
144 | 1 | rdata->callback = callback; | |
145 | 1 | rdata->user_data = user_data; | |
146 | 1 | rdata->regwrite = regwrite; | |
147 | |||
148 | 1 | aes_write_regv (dev, (const struct aes_regwrite *) regwrite, 1, | |
149 | read_regs_rq_cb, rdata); | ||
150 | 1 | } | |
151 | |||
152 | /* Read the value of a specific register from a register dump */ | ||
153 | static int | ||
154 | 48 | regval_from_dump (unsigned char *data, guint8 target) | |
155 | { | ||
156 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | if (*data != FIRST_AES2501_REG) |
157 | { | ||
158 | ✗ | fp_err ("not a register dump"); | |
159 | ✗ | return -1; | |
160 | } | ||
161 | |||
162 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | if (!(FIRST_AES2501_REG <= target && target <= LAST_AES2501_REG)) |
163 | { | ||
164 | ✗ | fp_err ("out of range"); | |
165 | ✗ | return -1; | |
166 | } | ||
167 | |||
168 | 48 | target -= FIRST_AES2501_REG; | |
169 | 48 | target *= 2; | |
170 | 48 | return data[target + 1]; | |
171 | } | ||
172 | |||
173 | static void | ||
174 | 54 | generic_write_regv_cb (FpImageDevice *dev, GError *error, | |
175 | void *user_data) | ||
176 | { | ||
177 | 54 | FpiSsm *ssm = user_data; | |
178 | |||
179 |
1/2✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
|
54 | if (!error) |
180 | 54 | fpi_ssm_next_state (ssm); | |
181 | else | ||
182 | ✗ | fpi_ssm_mark_failed (ssm, error); | |
183 | 54 | } | |
184 | |||
185 | /* read the specified number of bytes from the IN endpoint but throw them | ||
186 | * away, then increment the SSM */ | ||
187 | static void | ||
188 | 3 | generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev, | |
189 | size_t bytes) | ||
190 | { | ||
191 | 3 | FpiUsbTransfer *transfer; | |
192 | |||
193 | 3 | transfer = fpi_usb_transfer_new (dev); | |
194 | 3 | transfer->ssm = ssm; | |
195 | 3 | transfer->short_is_error = TRUE; | |
196 | 3 | fpi_usb_transfer_fill_bulk (transfer, EP_IN, bytes); | |
197 | 3 | fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, | |
198 | fpi_ssm_usb_transfer_cb, NULL); | ||
199 | 3 | } | |
200 | |||
201 | /****** IMAGE PROCESSING ******/ | ||
202 | |||
203 | static int | ||
204 | 48 | sum_histogram_values (unsigned char *data, guint8 threshold) | |
205 | { | ||
206 | 48 | int r = 0; | |
207 | 48 | int i; | |
208 | 48 | guint16 *histogram = (guint16 *) (data + 1); | |
209 | |||
210 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | if (*data != 0xde) |
211 | return -1; | ||
212 | |||
213 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | if (threshold > 0x0f) |
214 | return -1; | ||
215 | |||
216 | /* FIXME endianness */ | ||
217 |
2/2✓ Branch 0 taken 384 times.
✓ Branch 1 taken 48 times.
|
432 | for (i = threshold; i < 16; i++) |
218 | 384 | r += histogram[i]; | |
219 | |||
220 | return r; | ||
221 | } | ||
222 | |||
223 | /****** FINGER PRESENCE DETECTION ******/ | ||
224 | |||
225 | static const struct aes_regwrite finger_det_reqs[] = { | ||
226 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
227 | { AES2501_REG_EXCITCTRL, 0x40 }, | ||
228 | { AES2501_REG_DETCTRL, | ||
229 | AES2501_DETCTRL_DRATE_CONTINUOUS | AES2501_DETCTRL_SDELAY_31_MS }, | ||
230 | { AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US }, | ||
231 | { AES2501_REG_MEASDRV, AES2501_MEASDRV_MDRIVE_0_325 | AES2501_MEASDRV_MEASURE_SQUARE }, | ||
232 | { AES2501_REG_MEASFREQ, AES2501_MEASFREQ_2M }, | ||
233 | { AES2501_REG_DEMODPHASE1, DEMODPHASE_NONE }, | ||
234 | { AES2501_REG_DEMODPHASE2, DEMODPHASE_NONE }, | ||
235 | { AES2501_REG_CHANGAIN, | ||
236 | AES2501_CHANGAIN_STAGE2_4X | AES2501_CHANGAIN_STAGE1_16X }, | ||
237 | { AES2501_REG_ADREFHI, 0x44 }, | ||
238 | { AES2501_REG_ADREFLO, 0x34 }, | ||
239 | { AES2501_REG_STRTCOL, 0x16 }, | ||
240 | { AES2501_REG_ENDCOL, 0x16 }, | ||
241 | { AES2501_REG_DATFMT, AES2501_DATFMT_BIN_IMG | 0x08 }, | ||
242 | { AES2501_REG_TREG1, 0x70 }, | ||
243 | { 0xa2, 0x02 }, | ||
244 | { 0xa7, 0x00 }, | ||
245 | { AES2501_REG_TREGC, AES2501_TREGC_ENABLE }, | ||
246 | { AES2501_REG_TREGD, 0x1a }, | ||
247 | { 0, 0 }, | ||
248 | { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, | ||
249 | { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, | ||
250 | { AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE }, | ||
251 | }; | ||
252 | |||
253 | static void start_finger_detection (FpImageDevice *dev); | ||
254 | |||
255 | static void | ||
256 | 706 | finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *_dev, | |
257 | gpointer user_data, GError *error) | ||
258 | { | ||
259 | 706 | FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); | |
260 | 706 | unsigned char *data = transfer->buffer; | |
261 | 706 | int i; | |
262 | 706 | int sum = 0; | |
263 | |||
264 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 706 times.
|
706 | if (error) |
265 | { | ||
266 | ✗ | fpi_image_device_session_error (dev, error); | |
267 | ✗ | return; | |
268 | } | ||
269 | |||
270 | /* examine histogram to determine finger presence */ | ||
271 |
2/2✓ Branch 0 taken 5648 times.
✓ Branch 1 taken 706 times.
|
6354 | for (i = 1; i < 9; i++) |
272 | 5648 | sum += (data[i] & 0xf) + (data[i] >> 4); | |
273 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 705 times.
|
706 | if (sum > 20) |
274 | { | ||
275 | /* finger present, start capturing */ | ||
276 | 1 | fpi_image_device_report_finger_status (dev, TRUE); | |
277 | 1 | start_capture (dev); | |
278 | } | ||
279 | else | ||
280 | { | ||
281 | /* no finger, poll for a new histogram */ | ||
282 | 705 | start_finger_detection (dev); | |
283 | } | ||
284 | } | ||
285 | |||
286 | static void | ||
287 | 706 | finger_det_reqs_cb (FpImageDevice *dev, GError *error, | |
288 | void *user_data) | ||
289 | { | ||
290 | 706 | FpiUsbTransfer *transfer; | |
291 | |||
292 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 706 times.
|
706 | if (error) |
293 | { | ||
294 | ✗ | fpi_image_device_session_error (dev, error); | |
295 | ✗ | return; | |
296 | } | ||
297 | |||
298 | 706 | transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); | |
299 | 706 | transfer->short_is_error = TRUE; | |
300 | 706 | fpi_usb_transfer_fill_bulk (transfer, EP_IN, FINGER_DETECTION_LEN); | |
301 | 706 | fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, | |
302 | finger_det_data_cb, NULL); | ||
303 | } | ||
304 | |||
305 | static void | ||
306 | 706 | start_finger_detection (FpImageDevice *dev) | |
307 | { | ||
308 | 706 | FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev); | |
309 | |||
310 | 706 | G_DEBUG_HERE (); | |
311 | |||
312 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 706 times.
|
706 | if (self->deactivating) |
313 | { | ||
314 | ✗ | complete_deactivation (dev); | |
315 | ✗ | return; | |
316 | } | ||
317 | |||
318 | 706 | aes_write_regv (dev, finger_det_reqs, G_N_ELEMENTS (finger_det_reqs), | |
319 | finger_det_reqs_cb, NULL); | ||
320 | } | ||
321 | |||
322 | /****** CAPTURE ******/ | ||
323 | |||
324 | static const struct aes_regwrite capture_reqs_1[] = { | ||
325 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
326 | { 0, 0 }, | ||
327 | { AES2501_REG_EXCITCTRL, 0x40 }, | ||
328 | { AES2501_REG_DETCTRL, | ||
329 | AES2501_DETCTRL_SDELAY_31_MS | AES2501_DETCTRL_DRATE_CONTINUOUS }, | ||
330 | { AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US }, | ||
331 | { AES2501_REG_DEMODPHASE2, 0x7c }, | ||
332 | { AES2501_REG_MEASDRV, | ||
333 | AES2501_MEASDRV_MEASURE_SQUARE | AES2501_MEASDRV_MDRIVE_0_325 }, | ||
334 | { AES2501_REG_DEMODPHASE1, 0x24 }, | ||
335 | { AES2501_REG_CHWORD1, 0x00 }, | ||
336 | { AES2501_REG_CHWORD2, 0x6c }, | ||
337 | { AES2501_REG_CHWORD3, 0x09 }, | ||
338 | { AES2501_REG_CHWORD4, 0x54 }, | ||
339 | { AES2501_REG_CHWORD5, 0x78 }, | ||
340 | { 0xa2, 0x02 }, | ||
341 | { 0xa7, 0x00 }, | ||
342 | { 0xb6, 0x26 }, | ||
343 | { 0xb7, 0x1a }, | ||
344 | { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, | ||
345 | { AES2501_REG_IMAGCTRL, | ||
346 | AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE | | ||
347 | AES2501_IMAGCTRL_IMG_DATA_DISABLE }, | ||
348 | { AES2501_REG_STRTCOL, 0x10 }, | ||
349 | { AES2501_REG_ENDCOL, 0x1f }, | ||
350 | { AES2501_REG_CHANGAIN, | ||
351 | AES2501_CHANGAIN_STAGE1_2X | AES2501_CHANGAIN_STAGE2_2X }, | ||
352 | { AES2501_REG_ADREFHI, 0x70 }, | ||
353 | { AES2501_REG_ADREFLO, 0x20 }, | ||
354 | { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, | ||
355 | { AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE }, | ||
356 | }; | ||
357 | |||
358 | static const struct aes_regwrite capture_reqs_2[] = { | ||
359 | { AES2501_REG_IMAGCTRL, | ||
360 | AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE | | ||
361 | AES2501_IMAGCTRL_IMG_DATA_DISABLE }, | ||
362 | { AES2501_REG_STRTCOL, 0x10 }, | ||
363 | { AES2501_REG_ENDCOL, 0x1f }, | ||
364 | { AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_16X }, | ||
365 | { AES2501_REG_ADREFHI, 0x70 }, | ||
366 | { AES2501_REG_ADREFLO, 0x20 }, | ||
367 | { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, | ||
368 | }; | ||
369 | |||
370 | static struct aes_regwrite strip_scan_reqs[] = { | ||
371 | { AES2501_REG_IMAGCTRL, | ||
372 | AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE }, | ||
373 | { AES2501_REG_STRTCOL, 0x00 }, | ||
374 | { AES2501_REG_ENDCOL, 0x2f }, | ||
375 | { AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_16X }, | ||
376 | { AES2501_REG_ADREFHI, AES2501_ADREFHI_MAX_VALUE }, | ||
377 | { AES2501_REG_ADREFLO, 0x20 }, | ||
378 | { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, | ||
379 | }; | ||
380 | |||
381 | /* capture SM movement: | ||
382 | * write reqs and read data 1 + 2, | ||
383 | * request and read strip, | ||
384 | * jump back to request UNLESS there's no finger, in which case exit SM, | ||
385 | * report lack of finger presence, and move to finger detection */ | ||
386 | |||
387 | enum capture_states { | ||
388 | CAPTURE_WRITE_REQS_1, | ||
389 | CAPTURE_READ_DATA_1, | ||
390 | CAPTURE_WRITE_REQS_2, | ||
391 | CAPTURE_READ_DATA_2, | ||
392 | CAPTURE_REQUEST_STRIP, | ||
393 | CAPTURE_READ_STRIP, | ||
394 | CAPTURE_NUM_STATES, | ||
395 | }; | ||
396 | |||
397 | static void | ||
398 | 48 | capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *_dev, | |
399 | gpointer user_data, GError *error) | ||
400 | { | ||
401 | 48 | FpiSsm *ssm = transfer->ssm; | |
402 | 48 | unsigned char *stripdata; | |
403 | 48 | FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); | |
404 | 48 | FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (_dev); | |
405 | 48 | unsigned char *data = transfer->buffer; | |
406 | 48 | int sum; | |
407 | 48 | int threshold; | |
408 | |||
409 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | if (error) |
410 | { | ||
411 | ✗ | fpi_ssm_mark_failed (ssm, error); | |
412 | ✗ | return; | |
413 | } | ||
414 | |||
415 | 48 | threshold = regval_from_dump (data + 1 + 192 * 8 + 1 + 16 * 2 + 1 + 8, | |
416 | AES2501_REG_DATFMT); | ||
417 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | if (threshold < 0) |
418 | { | ||
419 | ✗ | fpi_ssm_mark_failed (ssm, | |
420 | fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); | ||
421 | ✗ | return; | |
422 | } | ||
423 | |||
424 | 48 | sum = sum_histogram_values (data + 1 + 192 * 8, threshold & 0x0f); | |
425 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | if (sum < 0) |
426 | { | ||
427 | ✗ | fpi_ssm_mark_failed (ssm, | |
428 | fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); | ||
429 | ✗ | return; | |
430 | } | ||
431 | 48 | fp_dbg ("sum=%d", sum); | |
432 | |||
433 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | if (sum < AES2501_SUM_LOW_THRESH) |
434 | { | ||
435 | 48 | strip_scan_reqs[4].value -= 0x8; | |
436 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 6 times.
|
48 | if (strip_scan_reqs[4].value < AES2501_ADREFHI_MIN_VALUE) |
437 | 42 | strip_scan_reqs[4].value = AES2501_ADREFHI_MIN_VALUE; | |
438 | } | ||
439 | ✗ | else if (sum > AES2501_SUM_HIGH_THRESH) | |
440 | { | ||
441 | ✗ | strip_scan_reqs[4].value += 0x8; | |
442 | ✗ | if (strip_scan_reqs[4].value > AES2501_ADREFHI_MAX_VALUE) | |
443 | ✗ | strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE; | |
444 | } | ||
445 | 48 | fp_dbg ("ADREFHI is %.2x", strip_scan_reqs[4].value); | |
446 | |||
447 | /* Sum is 0, maybe finger was removed? Wait for 3 empty frames | ||
448 | * to ensure | ||
449 | */ | ||
450 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 45 times.
|
48 | if (sum == 0) |
451 | { | ||
452 | 3 | self->no_finger_cnt++; | |
453 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if (self->no_finger_cnt == 3) |
454 | { | ||
455 | 1 | FpImage *img; | |
456 | |||
457 | 1 | self->strips = g_slist_reverse (self->strips); | |
458 | 1 | fpi_do_movement_estimation (&assembling_ctx, self->strips); | |
459 | 1 | img = fpi_assemble_frames (&assembling_ctx, | |
460 | self->strips); | ||
461 | 1 | img->flags |= FPI_IMAGE_PARTIAL; | |
462 | 1 | g_slist_free_full (self->strips, g_free); | |
463 | 1 | self->strips = NULL; | |
464 | 1 | self->strips_len = 0; | |
465 | 1 | fpi_image_device_image_captured (dev, img); | |
466 | 1 | fpi_image_device_report_finger_status (dev, FALSE); | |
467 | /* marking machine complete will re-trigger finger detection loop */ | ||
468 | 1 | fpi_ssm_mark_completed (ssm); | |
469 | } | ||
470 | else | ||
471 | { | ||
472 | 2 | fpi_ssm_jump_to_state (ssm, CAPTURE_REQUEST_STRIP); | |
473 | } | ||
474 | } | ||
475 | else | ||
476 | { | ||
477 | /* obtain next strip */ | ||
478 | /* FIXME: would preallocating strip buffers be a decent optimization? */ | ||
479 | 45 | struct fpi_frame *stripe = g_malloc (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame)); | |
480 | 45 | stripe->delta_x = 0; | |
481 | 45 | stripe->delta_y = 0; | |
482 | 45 | stripdata = stripe->data; | |
483 | 45 | memcpy (stripdata, data + 1, 192 * 8); | |
484 | 45 | self->no_finger_cnt = 0; | |
485 | 45 | self->strips = g_slist_prepend (self->strips, stripe); | |
486 | 45 | self->strips_len++; | |
487 | |||
488 | 45 | fpi_ssm_jump_to_state (ssm, CAPTURE_REQUEST_STRIP); | |
489 | } | ||
490 | } | ||
491 | |||
492 | static void | ||
493 | 100 | capture_run_state (FpiSsm *ssm, FpDevice *device) | |
494 | { | ||
495 | 100 | FpImageDevice *dev = FP_IMAGE_DEVICE (device); | |
496 | 100 | FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (device); | |
497 | |||
498 |
6/7✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 48 times.
✓ Branch 6 taken 48 times.
✗ Branch 7 not taken.
|
100 | switch (fpi_ssm_get_cur_state (ssm)) |
499 | { | ||
500 | 1 | case CAPTURE_WRITE_REQS_1: | |
501 | 1 | aes_write_regv (dev, capture_reqs_1, G_N_ELEMENTS (capture_reqs_1), | |
502 | generic_write_regv_cb, ssm); | ||
503 | 1 | break; | |
504 | |||
505 | 1 | case CAPTURE_READ_DATA_1: | |
506 | 1 | generic_read_ignore_data (ssm, device, READ_REGS_RESP_LEN); | |
507 | 1 | break; | |
508 | |||
509 | 1 | case CAPTURE_WRITE_REQS_2: | |
510 | 1 | aes_write_regv (dev, capture_reqs_2, G_N_ELEMENTS (capture_reqs_2), | |
511 | generic_write_regv_cb, ssm); | ||
512 | 1 | break; | |
513 | |||
514 | 1 | case CAPTURE_READ_DATA_2: | |
515 | 1 | generic_read_ignore_data (ssm, device, READ_REGS_RESP_LEN); | |
516 | 1 | break; | |
517 | |||
518 | 48 | case CAPTURE_REQUEST_STRIP: | |
519 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | if (self->deactivating) |
520 | ✗ | fpi_ssm_mark_completed (ssm); | |
521 | else | ||
522 | 48 | aes_write_regv (dev, strip_scan_reqs, G_N_ELEMENTS (strip_scan_reqs), | |
523 | generic_write_regv_cb, ssm); | ||
524 | break; | ||
525 | |||
526 | 48 | case CAPTURE_READ_STRIP: { | |
527 | 48 | FpiUsbTransfer *transfer; | |
528 | |||
529 | 48 | transfer = fpi_usb_transfer_new (device); | |
530 | 48 | transfer->ssm = ssm; | |
531 | 48 | transfer->short_is_error = TRUE; | |
532 | 48 | fpi_usb_transfer_fill_bulk (transfer, EP_IN, STRIP_CAPTURE_LEN); | |
533 | 48 | fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, | |
534 | capture_read_strip_cb, NULL); | ||
535 | 48 | break; | |
536 | } | ||
537 | } | ||
538 | 100 | ; | |
539 | 100 | } | |
540 | |||
541 | static void | ||
542 | 1 | capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) | |
543 | { | ||
544 | 1 | FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); | |
545 | 1 | FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (_dev); | |
546 | |||
547 | 1 | G_DEBUG_HERE (); | |
548 | |||
549 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (self->deactivating) |
550 | { | ||
551 | 1 | complete_deactivation (dev); | |
552 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_clear_pointer (&error, g_error_free); |
553 | } | ||
554 | ✗ | else if (error) | |
555 | { | ||
556 | ✗ | fpi_image_device_session_error (dev, error); | |
557 | } | ||
558 | else | ||
559 | { | ||
560 | ✗ | start_finger_detection (dev); | |
561 | } | ||
562 | 1 | } | |
563 | |||
564 | static void | ||
565 | 1 | start_capture (FpImageDevice *dev) | |
566 | { | ||
567 | 1 | FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev); | |
568 | 1 | FpiSsm *ssm; | |
569 | |||
570 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (self->deactivating) |
571 | { | ||
572 | ✗ | complete_deactivation (dev); | |
573 | ✗ | return; | |
574 | } | ||
575 | |||
576 | 1 | self->no_finger_cnt = 0; | |
577 | /* Reset gain */ | ||
578 | 1 | strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE; | |
579 | 1 | ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, | |
580 | CAPTURE_NUM_STATES); | ||
581 | 1 | G_DEBUG_HERE (); | |
582 | 1 | fpi_ssm_start (ssm, capture_sm_complete); | |
583 | } | ||
584 | |||
585 | /****** INITIALIZATION/DEINITIALIZATION ******/ | ||
586 | |||
587 | static const struct aes_regwrite init_1[] = { | ||
588 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
589 | { 0, 0 }, | ||
590 | { 0xb0, 0x27 }, /* Reserved? */ | ||
591 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
592 | { AES2501_REG_EXCITCTRL, 0x40 }, | ||
593 | { 0xff, 0x00 }, /* Reserved? */ | ||
594 | { 0xff, 0x00 }, /* Reserved? */ | ||
595 | { 0xff, 0x00 }, /* Reserved? */ | ||
596 | { 0xff, 0x00 }, /* Reserved? */ | ||
597 | { 0xff, 0x00 }, /* Reserved? */ | ||
598 | { 0xff, 0x00 }, /* Reserved? */ | ||
599 | { 0xff, 0x00 }, /* Reserved? */ | ||
600 | { 0xff, 0x00 }, /* Reserved? */ | ||
601 | { 0xff, 0x00 }, /* Reserved? */ | ||
602 | { 0xff, 0x00 }, /* Reserved? */ | ||
603 | { 0xff, 0x00 }, /* Reserved? */ | ||
604 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
605 | { AES2501_REG_EXCITCTRL, 0x40 }, | ||
606 | { AES2501_REG_DETCTRL, | ||
607 | AES2501_DETCTRL_DRATE_CONTINUOUS | AES2501_DETCTRL_SDELAY_31_MS }, | ||
608 | { AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US }, | ||
609 | { AES2501_REG_MEASDRV, | ||
610 | AES2501_MEASDRV_MDRIVE_0_325 | AES2501_MEASDRV_MEASURE_SQUARE }, | ||
611 | { AES2501_REG_MEASFREQ, AES2501_MEASFREQ_2M }, | ||
612 | { AES2501_REG_DEMODPHASE1, DEMODPHASE_NONE }, | ||
613 | { AES2501_REG_DEMODPHASE2, DEMODPHASE_NONE }, | ||
614 | { AES2501_REG_CHANGAIN, | ||
615 | AES2501_CHANGAIN_STAGE2_4X | AES2501_CHANGAIN_STAGE1_16X }, | ||
616 | { AES2501_REG_ADREFHI, 0x44 }, | ||
617 | { AES2501_REG_ADREFLO, 0x34 }, | ||
618 | { AES2501_REG_STRTCOL, 0x16 }, | ||
619 | { AES2501_REG_ENDCOL, 0x16 }, | ||
620 | { AES2501_REG_DATFMT, AES2501_DATFMT_BIN_IMG | 0x08 }, | ||
621 | { AES2501_REG_TREG1, 0x70 }, | ||
622 | { 0xa2, 0x02 }, | ||
623 | { 0xa7, 0x00 }, | ||
624 | { AES2501_REG_TREGC, AES2501_TREGC_ENABLE }, | ||
625 | { AES2501_REG_TREGD, 0x1a }, | ||
626 | { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, | ||
627 | { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, | ||
628 | { AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE }, | ||
629 | }; | ||
630 | |||
631 | static const struct aes_regwrite init_2[] = { | ||
632 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
633 | { AES2501_REG_EXCITCTRL, 0x40 }, | ||
634 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
635 | { AES2501_REG_AUTOCALOFFSET, 0x41 }, | ||
636 | { AES2501_REG_EXCITCTRL, 0x42 }, | ||
637 | { AES2501_REG_DETCTRL, 0x53 }, | ||
638 | { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, | ||
639 | }; | ||
640 | |||
641 | static const struct aes_regwrite init_3[] = { | ||
642 | { 0xff, 0x00 }, | ||
643 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
644 | { AES2501_REG_AUTOCALOFFSET, 0x41 }, | ||
645 | { AES2501_REG_EXCITCTRL, 0x42 }, | ||
646 | { AES2501_REG_DETCTRL, 0x53 }, | ||
647 | { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, | ||
648 | }; | ||
649 | |||
650 | static const struct aes_regwrite init_4[] = { | ||
651 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
652 | { AES2501_REG_EXCITCTRL, 0x40 }, | ||
653 | { 0xb0, 0x27 }, | ||
654 | { AES2501_REG_ENDROW, 0x0a }, | ||
655 | { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, | ||
656 | { AES2501_REG_DETCTRL, 0x45 }, | ||
657 | { AES2501_REG_AUTOCALOFFSET, 0x41 }, | ||
658 | }; | ||
659 | |||
660 | static const struct aes_regwrite init_5[] = { | ||
661 | { 0xb0, 0x27 }, | ||
662 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
663 | { AES2501_REG_EXCITCTRL, 0x40 }, | ||
664 | { 0xff, 0x00 }, | ||
665 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
666 | { AES2501_REG_EXCITCTRL, 0x40 }, | ||
667 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
668 | { AES2501_REG_EXCITCTRL, 0x40 }, | ||
669 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
670 | { AES2501_REG_EXCITCTRL, 0x40 }, | ||
671 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
672 | { AES2501_REG_EXCITCTRL, 0x40 }, | ||
673 | { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, | ||
674 | { AES2501_REG_EXCITCTRL, 0x40 }, | ||
675 | { AES2501_REG_CTRL1, AES2501_CTRL1_SCAN_RESET }, | ||
676 | { AES2501_REG_CTRL1, AES2501_CTRL1_SCAN_RESET }, | ||
677 | }; | ||
678 | |||
679 | enum activate_states { | ||
680 | WRITE_INIT_1, | ||
681 | READ_DATA_1, | ||
682 | WRITE_INIT_2, | ||
683 | READ_REGS, | ||
684 | WRITE_INIT_3, | ||
685 | WRITE_INIT_4, | ||
686 | WRITE_INIT_5, | ||
687 | ACTIVATE_NUM_STATES, | ||
688 | }; | ||
689 | |||
690 | static void | ||
691 | 1 | activate_read_regs_cb (FpImageDevice *dev, GError *error, | |
692 | unsigned char *regs, void *user_data) | ||
693 | { | ||
694 | 1 | FpiSsm *ssm = user_data; | |
695 | 1 | FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev); | |
696 | |||
697 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
698 | { | ||
699 | ✗ | fpi_ssm_mark_failed (ssm, error); | |
700 | } | ||
701 | else | ||
702 | { | ||
703 | 1 | fp_dbg ("reg 0xaf = %x", regs[0x5f]); | |
704 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | if (regs[0x5f] != 0x6b || ++self->read_regs_retry_count == 13) |
705 | 1 | fpi_ssm_jump_to_state (ssm, WRITE_INIT_4); | |
706 | else | ||
707 | ✗ | fpi_ssm_next_state (ssm); | |
708 | } | ||
709 | 1 | } | |
710 | |||
711 | static void | ||
712 | ✗ | activate_init3_cb (FpImageDevice *dev, GError *error, | |
713 | void *user_data) | ||
714 | { | ||
715 | ✗ | FpiSsm *ssm = user_data; | |
716 | |||
717 | ✗ | if (!error) | |
718 | ✗ | fpi_ssm_jump_to_state (ssm, READ_REGS); | |
719 | else | ||
720 | ✗ | fpi_ssm_mark_failed (ssm, error); | |
721 | ✗ | } | |
722 | |||
723 | static void | ||
724 | 6 | activate_run_state (FpiSsm *ssm, FpDevice *_dev) | |
725 | { | ||
726 | 6 | FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); | |
727 | |||
728 | /* This state machine isn't as linear as it may appear. After doing init1 | ||
729 | * and init2 register configuration writes, we have to poll a register | ||
730 | * waiting for a specific value. READ_REGS checks the register value, and | ||
731 | * if we're ready to move on, we jump to init4. Otherwise, we write init3 | ||
732 | * and then jump back to READ_REGS. In a synchronous model: | ||
733 | |||
734 | [...] | ||
735 | aes_write_regv(init_2); | ||
736 | read_regs(into buffer); | ||
737 | i = 0; | ||
738 | while (buffer[0x5f] == 0x6b) { | ||
739 | aes_write_regv(init_3); | ||
740 | read_regs(into buffer); | ||
741 | if (++i == 13) | ||
742 | break; | ||
743 | } | ||
744 | aes_write_regv(init_4); | ||
745 | */ | ||
746 | |||
747 |
6/8✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
6 | switch (fpi_ssm_get_cur_state (ssm)) |
748 | { | ||
749 | 1 | case WRITE_INIT_1: | |
750 | 1 | aes_write_regv (dev, init_1, G_N_ELEMENTS (init_1), | |
751 | generic_write_regv_cb, ssm); | ||
752 | 1 | break; | |
753 | |||
754 | 1 | case READ_DATA_1: | |
755 | 1 | fp_dbg ("read data 1"); | |
756 | 1 | generic_read_ignore_data (ssm, _dev, FINGER_DETECTION_LEN); | |
757 | 1 | break; | |
758 | |||
759 | 1 | case WRITE_INIT_2: | |
760 | 1 | aes_write_regv (dev, init_2, G_N_ELEMENTS (init_2), | |
761 | generic_write_regv_cb, ssm); | ||
762 | 1 | break; | |
763 | |||
764 | 1 | case READ_REGS: | |
765 | 1 | read_regs (dev, activate_read_regs_cb, ssm); | |
766 | 1 | break; | |
767 | |||
768 | ✗ | case WRITE_INIT_3: | |
769 | ✗ | aes_write_regv (dev, init_3, G_N_ELEMENTS (init_3), | |
770 | activate_init3_cb, ssm); | ||
771 | ✗ | break; | |
772 | |||
773 | 1 | case WRITE_INIT_4: | |
774 | 1 | aes_write_regv (dev, init_4, G_N_ELEMENTS (init_4), | |
775 | generic_write_regv_cb, ssm); | ||
776 | 1 | break; | |
777 | |||
778 | 1 | case WRITE_INIT_5: | |
779 | 1 | aes_write_regv (dev, init_5, G_N_ELEMENTS (init_5), | |
780 | generic_write_regv_cb, ssm); | ||
781 | 1 | break; | |
782 | } | ||
783 | 6 | } | |
784 | |||
785 | static void | ||
786 | 1 | activate_sm_complete (FpiSsm *ssm, FpDevice *dev, GError *error) | |
787 | { | ||
788 | 1 | fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error); | |
789 | |||
790 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (!error) |
791 | 1 | start_finger_detection (FP_IMAGE_DEVICE (dev)); | |
792 | 1 | } | |
793 | |||
794 | static void | ||
795 | 1 | dev_activate (FpImageDevice *dev) | |
796 | { | ||
797 | 1 | FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev); | |
798 | 1 | FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, | |
799 | ACTIVATE_NUM_STATES); | ||
800 | |||
801 | 1 | self->read_regs_retry_count = 0; | |
802 | 1 | fpi_ssm_start (ssm, activate_sm_complete); | |
803 | 1 | } | |
804 | |||
805 | static void | ||
806 | 1 | dev_deactivate (FpImageDevice *dev) | |
807 | { | ||
808 | 1 | FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev); | |
809 | |||
810 | /* FIXME: audit cancellation points, probably need more, specifically | ||
811 | * in error handling paths? */ | ||
812 | 1 | self->deactivating = TRUE; | |
813 | 1 | } | |
814 | |||
815 | static void | ||
816 | 1 | complete_deactivation (FpImageDevice *dev) | |
817 | { | ||
818 | 1 | FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev); | |
819 | |||
820 | 1 | G_DEBUG_HERE (); | |
821 | |||
822 | /* FIXME: if we're in the middle of a scan, we should cancel the scan. | ||
823 | * maybe we can do this with a master reset, unconditionally? */ | ||
824 | |||
825 | 1 | self->deactivating = FALSE; | |
826 | 1 | g_slist_free (self->strips); | |
827 | 1 | self->strips = NULL; | |
828 | 1 | self->strips_len = 0; | |
829 | 1 | fpi_image_device_deactivate_complete (dev, NULL); | |
830 | 1 | } | |
831 | |||
832 | static void | ||
833 | 1 | dev_init (FpImageDevice *dev) | |
834 | { | ||
835 | 1 | GError *error = NULL; | |
836 | |||
837 | /* FIXME check endpoints */ | ||
838 | |||
839 | 1 | g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error); | |
840 | 1 | fpi_image_device_open_complete (dev, error); | |
841 | 1 | } | |
842 | |||
843 | static void | ||
844 | 1 | dev_deinit (FpImageDevice *dev) | |
845 | { | ||
846 | 1 | GError *error = NULL; | |
847 | |||
848 | 1 | g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), | |
849 | 0, 0, &error); | ||
850 | 1 | fpi_image_device_close_complete (dev, error); | |
851 | 1 | } | |
852 | |||
853 | static const FpIdEntry id_table[] = { | ||
854 | { .vid = 0x08ff, .pid = 0x2500, },/* AES2500 */ | ||
855 | { .vid = 0x08ff, .pid = 0x2580, },/* AES2501 */ | ||
856 | { .vid = 0, .pid = 0, .driver_data = 0 }, | ||
857 | }; | ||
858 | |||
859 | static void | ||
860 | 1 | fpi_device_aes2501_init (FpiDeviceAes2501 *self) | |
861 | { | ||
862 | 1 | } | |
863 | static void | ||
864 | 120 | fpi_device_aes2501_class_init (FpiDeviceAes2501Class *klass) | |
865 | { | ||
866 | 120 | FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); | |
867 | 120 | FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); | |
868 | |||
869 | 120 | dev_class->id = "aes2501"; | |
870 | 120 | dev_class->full_name = "AuthenTec AES2501"; | |
871 | 120 | dev_class->type = FP_DEVICE_TYPE_USB; | |
872 | 120 | dev_class->id_table = id_table; | |
873 | 120 | dev_class->scan_type = FP_SCAN_TYPE_SWIPE; | |
874 | |||
875 | 120 | img_class->img_open = dev_init; | |
876 | 120 | img_class->img_close = dev_deinit; | |
877 | 120 | img_class->activate = dev_activate; | |
878 | 120 | img_class->deactivate = dev_deactivate; | |
879 | |||
880 | 120 | img_class->img_width = IMAGE_WIDTH; | |
881 | 120 | img_class->img_height = -1; | |
882 | } | ||
883 |