Add upeksonly driver for UPEK TouchStrip sensor-only devices
[libfprint.git] / libfprint / aeslib.c
blobda9be012b3ef127ac1e8961967655f956ef09e43
1 /*
2 * Shared functions between libfprint Authentec drivers
3 * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #define FP_COMPONENT "aeslib"
22 #include <errno.h>
24 #include <libusb.h>
25 #include <glib.h>
27 #include "fp_internal.h"
28 #include "aeslib.h"
30 #define MAX_REGWRITES_PER_REQUEST 16
32 #define BULK_TIMEOUT 4000
33 #define EP_IN (1 | LIBUSB_ENDPOINT_IN)
34 #define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
36 struct write_regv_data {
37 struct fp_img_dev *imgdev;
38 unsigned int num_regs;
39 const struct aes_regwrite *regs;
40 unsigned int offset;
41 aes_write_regv_cb callback;
42 void *user_data;
45 static void continue_write_regv(struct write_regv_data *wdata);
47 /* libusb bulk callback for regv write completion transfer. continues the
48 * transaction */
49 static void write_regv_trf_complete(struct libusb_transfer *transfer)
51 struct write_regv_data *wdata = transfer->user_data;
53 if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
54 wdata->callback(wdata->imgdev, -EIO, wdata->user_data);
55 else if (transfer->length != transfer->actual_length)
56 wdata->callback(wdata->imgdev, -EPROTO, wdata->user_data);
57 else
58 continue_write_regv(wdata);
60 g_free(transfer->buffer);
61 libusb_free_transfer(transfer);
64 /* write from wdata->offset to upper_bound (inclusive) of wdata->regs */
65 static int do_write_regv(struct write_regv_data *wdata, int upper_bound)
67 unsigned int offset = wdata->offset;
68 unsigned int num = upper_bound - offset + 1;
69 size_t alloc_size = num * 2;
70 unsigned char *data = g_malloc(alloc_size);
71 unsigned int i;
72 size_t data_offset = 0;
73 struct libusb_transfer *transfer = libusb_alloc_transfer(0);
74 int r;
76 if (!transfer) {
77 g_free(data);
78 return -ENOMEM;
81 for (i = offset; i < offset + num; i++) {
82 const struct aes_regwrite *regwrite = &wdata->regs[i];
83 data[data_offset++] = regwrite->reg;
84 data[data_offset++] = regwrite->value;
87 libusb_fill_bulk_transfer(transfer, wdata->imgdev->udev, EP_OUT, data,
88 alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT);
89 r = libusb_submit_transfer(transfer);
90 if (r < 0) {
91 g_free(data);
92 libusb_free_transfer(transfer);
95 return r;
98 /* write the next batch of registers to be written, or if there are no more,
99 * indicate completion to the caller */
100 static void continue_write_regv(struct write_regv_data *wdata)
102 unsigned int offset = wdata->offset;
103 unsigned int regs_remaining;
104 unsigned int limit;
105 unsigned int upper_bound;
106 int i;
107 int r;
109 /* skip all zeros and ensure there is still work to do */
110 while (TRUE) {
111 if (offset >= wdata->num_regs) {
112 fp_dbg("all registers written");
113 wdata->callback(wdata->imgdev, 0, wdata->user_data);
114 return;
116 if (wdata->regs[offset].reg)
117 break;
118 offset++;
121 wdata->offset = offset;
122 regs_remaining = wdata->num_regs - offset;
123 limit = MIN(regs_remaining, MAX_REGWRITES_PER_REQUEST);
124 upper_bound = offset + limit - 1;
126 /* determine if we can write the entire of the regs at once, or if there
127 * is a zero dividing things up */
128 for (i = offset; i <= upper_bound; i++)
129 if (!wdata->regs[i].reg) {
130 upper_bound = i - 1;
131 break;
134 r = do_write_regv(wdata, upper_bound);
135 if (r < 0) {
136 wdata->callback(wdata->imgdev, r, wdata->user_data);
137 return;
140 wdata->offset = upper_bound + 1;
143 /* write a load of registers to the device, combining multiple writes in a
144 * single URB up to a limit. insert writes to non-existent register 0 to force
145 * specific groups of writes to be separated by different URBs. */
146 void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
147 unsigned int num_regs, aes_write_regv_cb callback, void *user_data)
149 struct write_regv_data *wdata = g_malloc(sizeof(*wdata));
150 fp_dbg("write %d regs", num_regs);
151 wdata->imgdev = dev;
152 wdata->num_regs = num_regs;
153 wdata->regs = regs;
154 wdata->offset = 0;
155 wdata->callback = callback;
156 wdata->user_data = user_data;
157 continue_write_regv(wdata);
160 void aes_assemble_image(unsigned char *input, size_t width, size_t height,
161 unsigned char *output)
163 size_t row, column;
165 for (column = 0; column < width; column++) {
166 for (row = 0; row < height; row += 2) {
167 output[width * row + column] = (*input & 0x07) * 36;
168 output[width * (row + 1) + column] = ((*input & 0x70) >> 4) * 36;
169 input++;