1 /*
2 * UPEK TouchChip driver for libfprint
3 * Copyright (C) 2007 Jan-Michael Brummer <buzz2@gmx.de>
4 * Copyright (C) 2012 Vasily Khoruzhick <anarsoul@gmail.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #define FP_COMPONENT "upektc"
22
23 #include <errno.h>
24 #include <string.h>
25 #include <libusb.h>
26 #include <fp_internal.h>
27
28 #include "upektc.h"
29 #include "driver_ids.h"
30
31 #define UPEKTC_EP_IN (2 | LIBUSB_ENDPOINT_IN)
32 #define UPEKTC_EP_OUT (3 | LIBUSB_ENDPOINT_OUT)
33 #define UPEKET_EP_IN (1 | LIBUSB_ENDPOINT_IN)
34 #define UPEKET_EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
35 #define BULK_TIMEOUT 4000
36
37 struct upektc_dev {
38 gboolean deactivating;
39 const struct setup_cmd *setup_commands;
40 size_t setup_commands_len;
41 int ep_in;
42 int ep_out;
43 int init_idx;
44 int sum_threshold;
45 };
46
47 enum upektc_driver_data {
48 UPEKTC_2015,
49 UPEKTC_3001,
50 };
51
52 static void start_capture(struct fp_img_dev *dev);
53 static void complete_deactivation(struct fp_img_dev *dev);
54 static void start_finger_detection(struct fp_img_dev *dev);
55
56 /****** INITIALIZATION/DEINITIALIZATION ******/
57
58 enum activate_states {
59 WRITE_INIT,
60 READ_DATA,
61 ACTIVATE_NUM_STATES,
62 };
63
upektc_next_init_cmd(struct fpi_ssm * ssm)64 static void upektc_next_init_cmd(struct fpi_ssm *ssm)
65 {
66 struct fp_img_dev *dev = ssm->priv;
67 struct upektc_dev *upekdev = dev->priv;
68
69 upekdev->init_idx += 1;
70 if (upekdev->init_idx == upekdev->setup_commands_len)
71 fpi_ssm_mark_completed(ssm);
72 else
73 fpi_ssm_jump_to_state(ssm, WRITE_INIT);
74 }
75
write_init_cb(struct libusb_transfer * transfer)76 static void write_init_cb(struct libusb_transfer *transfer)
77 {
78 struct fpi_ssm *ssm = transfer->user_data;
79 struct fp_img_dev *dev = ssm->priv;
80 struct upektc_dev *upekdev = dev->priv;
81
82 if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
83 (transfer->length == transfer->actual_length)) {
84 if (upekdev->setup_commands[upekdev->init_idx].response_len)
85 fpi_ssm_next_state(ssm);
86 else
87 upektc_next_init_cmd(ssm);
88 } else {
89 fpi_ssm_mark_aborted(ssm, -EIO);
90 }
91 libusb_free_transfer(transfer);
92 }
93
read_init_data_cb(struct libusb_transfer * transfer)94 static void read_init_data_cb(struct libusb_transfer *transfer)
95 {
96 struct fpi_ssm *ssm = transfer->user_data;
97
98 if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
99 upektc_next_init_cmd(ssm);
100 else
101 fpi_ssm_mark_aborted(ssm, -EIO);
102 g_free(transfer->buffer);
103 libusb_free_transfer(transfer);
104 }
105
activate_run_state(struct fpi_ssm * ssm)106 static void activate_run_state(struct fpi_ssm *ssm)
107 {
108 struct fp_img_dev *dev = ssm->priv;
109 struct upektc_dev *upekdev = dev->priv;
110 int r;
111
112 switch (ssm->cur_state) {
113 case WRITE_INIT:
114 {
115 struct libusb_transfer *transfer = libusb_alloc_transfer(0);
116 if (!transfer) {
117 fpi_ssm_mark_aborted(ssm, -ENOMEM);
118 return;
119 }
120 libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_out,
121 (unsigned char*)upekdev->setup_commands[upekdev->init_idx].cmd,
122 UPEKTC_CMD_LEN, write_init_cb, ssm, BULK_TIMEOUT);
123 r = libusb_submit_transfer(transfer);
124 if (r < 0) {
125 libusb_free_transfer(transfer);
126 fpi_ssm_mark_aborted(ssm, -ENOMEM);
127 }
128 }
129 break;
130 case READ_DATA:
131 {
132 struct libusb_transfer *transfer = libusb_alloc_transfer(0);
133 unsigned char *data;
134
135 if (!transfer) {
136 fpi_ssm_mark_aborted(ssm, -ENOMEM);
137 break;
138 }
139
140 data = g_malloc(upekdev->setup_commands[upekdev->init_idx].response_len);
141 libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_in, data,
142 upekdev->setup_commands[upekdev->init_idx].response_len,
143 read_init_data_cb, ssm, BULK_TIMEOUT);
144
145 r = libusb_submit_transfer(transfer);
146 if (r < 0) {
147 g_free(data);
148 libusb_free_transfer(transfer);
149 fpi_ssm_mark_aborted(ssm, r);
150 }
151 }
152 break;
153 }
154 }
155
activate_sm_complete(struct fpi_ssm * ssm)156 static void activate_sm_complete(struct fpi_ssm *ssm)
157 {
158 struct fp_img_dev *dev = ssm->priv;
159 fp_dbg("status %d", ssm->error);
160 fpi_imgdev_activate_complete(dev, ssm->error);
161
162 if (!ssm->error)
163 start_finger_detection(dev);
164 fpi_ssm_free(ssm);
165 }
166
167
168 /****** FINGER PRESENCE DETECTION ******/
169
finger_present(unsigned char * img,size_t len,int sum_threshold)170 static int finger_present(unsigned char *img, size_t len, int sum_threshold)
171 {
172 int i, sum;
173
174 sum = 0;
175
176 for (i = 0; i < len; i++) {
177 if (img[i] < 160) {
178 sum++;
179 }
180 }
181
182 fp_dbg("finger_present: sum is %d\n", sum);
183 return sum < sum_threshold ? 0 : 1;
184 }
185
finger_det_data_cb(struct libusb_transfer * transfer)186 static void finger_det_data_cb(struct libusb_transfer *transfer)
187 {
188 struct fp_img_dev *dev = transfer->user_data;
189 struct upektc_dev *upekdev = dev->priv;
190 unsigned char *data = transfer->buffer;
191
192 if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
193 fp_dbg("data transfer status %d\n", transfer->status);
194 fpi_imgdev_session_error(dev, -EIO);
195 goto out;
196 } else if (transfer->length != transfer->actual_length) {
197 fp_dbg("expected %d, got %d bytes", transfer->length,
198 transfer->actual_length);
199 fpi_imgdev_session_error(dev, -EPROTO);
200 }
201
202 if (finger_present(data, IMAGE_SIZE, upekdev->sum_threshold)) {
203 /* finger present, start capturing */
204 fpi_imgdev_report_finger_status(dev, TRUE);
205 start_capture(dev);
206 } else {
207 /* no finger, poll for a new histogram */
208 start_finger_detection(dev);
209 }
210
211 out:
212 g_free(data);
213 libusb_free_transfer(transfer);
214 }
215
finger_det_cmd_cb(struct libusb_transfer * t)216 static void finger_det_cmd_cb(struct libusb_transfer *t)
217 {
218 struct libusb_transfer *transfer;
219 unsigned char *data;
220 int r;
221 struct fp_img_dev *dev = t->user_data;
222 struct upektc_dev *upekdev = dev->priv;
223
224 if (t->status != LIBUSB_TRANSFER_COMPLETED) {
225 fp_dbg("req transfer status %d\n", t->status);
226 fpi_imgdev_session_error(dev, -EIO);
227 goto exit_free_transfer;
228 } else if (t->length != t->actual_length) {
229 fp_dbg("expected %d, sent %d bytes", t->length, t->actual_length);
230 fpi_imgdev_session_error(dev, -EPROTO);
231 goto exit_free_transfer;
232 }
233
234 transfer = libusb_alloc_transfer(0);
235 if (!transfer) {
236 fpi_imgdev_session_error(dev, -ENOMEM);
237 goto exit_free_transfer;
238 }
239
240 data = g_malloc(IMAGE_SIZE);
241 libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_in, data, IMAGE_SIZE,
242 finger_det_data_cb, dev, BULK_TIMEOUT);
243
244 r = libusb_submit_transfer(transfer);
245 if (r < 0) {
246 g_free(data);
247 libusb_free_transfer(transfer);
248 fpi_imgdev_session_error(dev, r);
249 }
250 exit_free_transfer:
251 libusb_free_transfer(t);
252 }
253
start_finger_detection(struct fp_img_dev * dev)254 static void start_finger_detection(struct fp_img_dev *dev)
255 {
256 int r;
257 struct upektc_dev *upekdev = dev->priv;
258 struct libusb_transfer *transfer;
259 fp_dbg("");
260
261 if (upekdev->deactivating) {
262 complete_deactivation(dev);
263 return;
264 }
265
266 transfer = libusb_alloc_transfer(0);
267 if (!transfer) {
268 fpi_imgdev_session_error(dev, -ENOMEM);
269 return;
270 }
271 libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_out,
272 (unsigned char *)scan_cmd, UPEKTC_CMD_LEN,
273 finger_det_cmd_cb, dev, BULK_TIMEOUT);
274 r = libusb_submit_transfer(transfer);
275 if (r < 0) {
276 libusb_free_transfer(transfer);
277 fpi_imgdev_session_error(dev, r);
278 }
279 }
280
281 /****** CAPTURE ******/
282
283 enum capture_states {
284 CAPTURE_WRITE_CMD,
285 CAPTURE_READ_DATA,
286 CAPTURE_NUM_STATES,
287 };
288
capture_cmd_cb(struct libusb_transfer * transfer)289 static void capture_cmd_cb(struct libusb_transfer *transfer)
290 {
291 struct fpi_ssm *ssm = transfer->user_data;
292
293 if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
294 (transfer->length == transfer->actual_length)) {
295 fpi_ssm_next_state(ssm);
296 } else {
297 fpi_ssm_mark_aborted(ssm, -EIO);
298 }
299 libusb_free_transfer(transfer);
300 }
301
capture_read_data_cb(struct libusb_transfer * transfer)302 static void capture_read_data_cb(struct libusb_transfer *transfer)
303 {
304 struct fpi_ssm *ssm = transfer->user_data;
305 struct fp_img_dev *dev = ssm->priv;
306 unsigned char *data = transfer->buffer;
307 struct fp_img *img;
308
309 if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
310 fp_dbg("request is not completed, %d", transfer->status);
311 fpi_ssm_mark_aborted(ssm, -EIO);
312 goto out;
313 } else if (transfer->length != transfer->actual_length) {
314 fp_dbg("expected %d, sent %d bytes", transfer->length, transfer->actual_length);
315 fpi_ssm_mark_aborted(ssm, -EPROTO);
316 goto out;
317 }
318
319 img = fpi_img_new(IMAGE_SIZE);
320 memcpy(img->data, data, IMAGE_SIZE);
321 fpi_imgdev_image_captured(dev, img);
322 fpi_imgdev_report_finger_status(dev, FALSE);
323 fpi_ssm_mark_completed(ssm);
324 out:
325 g_free(transfer->buffer);
326 libusb_free_transfer(transfer);
327 }
328
capture_run_state(struct fpi_ssm * ssm)329 static void capture_run_state(struct fpi_ssm *ssm)
330 {
331 struct fp_img_dev *dev = ssm->priv;
332 struct upektc_dev *upekdev = dev->priv;
333 int r;
334
335 switch (ssm->cur_state) {
336 case CAPTURE_WRITE_CMD:
337 {
338 struct libusb_transfer *transfer = libusb_alloc_transfer(0);
339 if (!transfer) {
340 fpi_ssm_mark_aborted(ssm, -ENOMEM);
341 return;
342 }
343 libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_out,
344 (unsigned char *)scan_cmd, UPEKTC_CMD_LEN,
345 capture_cmd_cb, ssm, BULK_TIMEOUT);
346 r = libusb_submit_transfer(transfer);
347 if (r < 0) {
348 libusb_free_transfer(transfer);
349 fpi_ssm_mark_aborted(ssm, -ENOMEM);
350 }
351 }
352 break;
353 case CAPTURE_READ_DATA:
354 {
355 struct libusb_transfer *transfer = libusb_alloc_transfer(0);
356 unsigned char *data;
357
358 if (!transfer) {
359 fpi_ssm_mark_aborted(ssm, -ENOMEM);
360 break;
361 }
362
363 data = g_malloc(IMAGE_SIZE);
364 libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_in, data, IMAGE_SIZE,
365 capture_read_data_cb, ssm, BULK_TIMEOUT);
366
367 r = libusb_submit_transfer(transfer);
368 if (r < 0) {
369 g_free(data);
370 libusb_free_transfer(transfer);
371 fpi_ssm_mark_aborted(ssm, r);
372 }
373 }
374 break;
375 };
376 }
377
capture_sm_complete(struct fpi_ssm * ssm)378 static void capture_sm_complete(struct fpi_ssm *ssm)
379 {
380 struct fp_img_dev *dev = ssm->priv;
381 struct upektc_dev *upekdev = dev->priv;
382
383 fp_dbg("Capture completed");
384 if (upekdev->deactivating)
385 complete_deactivation(dev);
386 else if (ssm->error)
387 fpi_imgdev_session_error(dev, ssm->error);
388 else
389 start_finger_detection(dev);
390 fpi_ssm_free(ssm);
391 }
392
start_capture(struct fp_img_dev * dev)393 static void start_capture(struct fp_img_dev *dev)
394 {
395 struct upektc_dev *upekdev = dev->priv;
396 struct fpi_ssm *ssm;
397
398 if (upekdev->deactivating) {
399 complete_deactivation(dev);
400 return;
401 }
402
403 ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
404 fp_dbg("");
405 ssm->priv = dev;
406 fpi_ssm_start(ssm, capture_sm_complete);
407 }
408
dev_activate(struct fp_img_dev * dev,enum fp_imgdev_state state)409 static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
410 {
411 struct upektc_dev *upekdev = dev->priv;
412 struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
413 ACTIVATE_NUM_STATES);
414 ssm->priv = dev;
415 upekdev->init_idx = 0;
416 fpi_ssm_start(ssm, activate_sm_complete);
417 return 0;
418 }
419
dev_deactivate(struct fp_img_dev * dev)420 static void dev_deactivate(struct fp_img_dev *dev)
421 {
422 struct upektc_dev *upekdev = dev->priv;
423
424 upekdev->deactivating = TRUE;
425 }
426
complete_deactivation(struct fp_img_dev * dev)427 static void complete_deactivation(struct fp_img_dev *dev)
428 {
429 struct upektc_dev *upekdev = dev->priv;
430 fp_dbg("");
431
432 upekdev->deactivating = FALSE;
433 fpi_imgdev_deactivate_complete(dev);
434 }
435
dev_init(struct fp_img_dev * dev,unsigned long driver_data)436 static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
437 {
438 /* TODO check that device has endpoints we're using */
439 int r;
440 struct upektc_dev *upekdev;
441
442 r = libusb_claim_interface(dev->udev, 0);
443 if (r < 0) {
444 fp_err("could not claim interface 0: %s", libusb_error_name(r));
445 return r;
446 }
447
448 dev->priv = upekdev = g_malloc0(sizeof(struct upektc_dev));
449 switch (driver_data) {
450 case UPEKTC_2015:
451 upekdev->ep_in = UPEKTC_EP_IN;
452 upekdev->ep_out = UPEKTC_EP_OUT;
453 upekdev->setup_commands = upektc_setup_commands;
454 upekdev->setup_commands_len = array_n_elements(upektc_setup_commands);
455 upekdev->sum_threshold = UPEKTC_SUM_THRESHOLD;
456 break;
457 case UPEKTC_3001:
458 upekdev->ep_in = UPEKET_EP_IN;
459 upekdev->ep_out = UPEKET_EP_OUT;
460 upekdev->setup_commands = upeket_setup_commands;
461 upekdev->setup_commands_len = array_n_elements(upeket_setup_commands);
462 upekdev->sum_threshold = UPEKET_SUM_THRESHOLD;
463 break;
464 default:
465 fp_err("Device variant %d is not known\n", driver_data);
466 g_free(upekdev);
467 dev->priv = NULL;
468 return -ENODEV;
469 break;
470 }
471 fpi_imgdev_open_complete(dev, 0);
472 return 0;
473 }
474
dev_deinit(struct fp_img_dev * dev)475 static void dev_deinit(struct fp_img_dev *dev)
476 {
477 g_free(dev->priv);
478 libusb_release_interface(dev->udev, 0);
479 fpi_imgdev_close_complete(dev);
480 }
481
482 static const struct usb_id id_table[] = {
483 { .vendor = 0x0483, .product = 0x2015, .driver_data = UPEKTC_2015 },
484 { .vendor = 0x147e, .product = 0x3001, .driver_data = UPEKTC_3001 },
485 { 0, 0, 0, },
486 };
487
488 struct fp_img_driver upektc_driver = {
489 .driver = {
490 .id = UPEKTC_ID,
491 .name = FP_COMPONENT,
492 .full_name = "UPEK TouchChip/Eikon Touch 300",
493 .id_table = id_table,
494 .scan_type = FP_SCAN_TYPE_PRESS,
495 },
496 .flags = 0,
497 .img_height = IMAGE_HEIGHT,
498 .img_width = IMAGE_WIDTH,
499
500 .bz3_threshold = 30,
501 .open = dev_init,
502 .close = dev_deinit,
503 .activate = dev_activate,
504 .deactivate = dev_deactivate,
505 };
506