upekts.c 41.5 KB
Newer Older
1
2
/*
 * UPEK TouchStrip driver for libfprint
3
 * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
4
 *
5
6
7
 * Based in part on libthinkfinger:
 * Copyright (C) 2006-2007 Timo Hoenig <thoenig@suse.de>
 * Copyright (C) 2006 Pavel Machek <pavel@suse.cz>
8
 *
9
10
11
 * LGPL CRC code copied from GStreamer-0.10.10:
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
 * Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
Daniel Drake's avatar
Daniel Drake committed
12
13
14
15
16

 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; version
 * 2.1 of the License.
17
 *
Daniel Drake's avatar
Daniel Drake committed
18
 * This library is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Daniel Drake's avatar
Daniel Drake committed
20
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
22
 *
Daniel Drake's avatar
Daniel Drake committed
23
24
25
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26
27
 */

28
29
#define FP_COMPONENT "upekts"

30
#include "drivers_api.h"
31

32
33
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
34
35
#define TIMEOUT 5000

36
37
38
#define MSG_READ_BUF_SIZE 0x40
#define MAX_DATA_IN_READ_BUF (MSG_READ_BUF_SIZE - 9)

39
struct upekts_dev {
40
41
42
43
	gboolean enroll_passed;
	gboolean first_verify_iteration;
	gboolean stop_verify;
	uint8_t seq; /* FIXME: improve/automate seq handling */
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
};

static const uint16_t crc_table[256] = {
	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
	0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
	0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
	0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
	0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
	0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
	0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
	0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
	0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
	0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
	0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
	0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
	0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
	0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
	0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
	0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
	0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
	0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
	0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
	0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
	0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
	0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
	0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
	0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
	0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
	0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
	0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
	0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
	0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
	0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
	0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
	0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};

static uint16_t udf_crc(unsigned char *buffer, size_t size)
{
	uint16_t crc = 0;
	while (size--)
    	crc = (uint16_t) ((crc << 8) ^
			crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]);
	return crc;
}

/*
 * MESSAGE FORMAT
 * 
 * Messages to and from the device have the same format.
 *
 * Byte-wise:
 * 		'C' 'i' 'a' 'o' A B L <DATA> C1 C2
 *
Daniel Drake's avatar
Daniel Drake committed
98
99
100
101
 * Ciao prefixes all messages. The rightmost 4 bits of B become the uppermost
 * 4 bits of L, and when combined with the lower 8 bits listed as 'L', L is
 * the length of the data, <DATA> is L bytes long. C1 and C2 are the
 * UDF-CRC16 for the whole message minus the Ciao prefix.
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
 *
 * When the device wants to command the driver to do something, it sends
 * a message where B=0 and A!=0. The A value indicates the type of command.
 * If the system is expected to respond to the command, it sends a message back
 * with B=0 and A incremented.
 *
 * When the driver sends a command to the device, A=0 and B is used as a
 * sequence counter. It starts at 0, increments by 0x10 on each command, and 
 * wraps around.
 * After each command is sent, the device responds with another message
 * indicating completion of the command including any data that was requested.
 * This message has the same A and B values.
 *
 * When the driver is sending commands as above, and when the device is
 * responding, the <DATA> seems to follow this structure:
 *
Daniel Drake's avatar
Daniel Drake committed
118
 * 		28 L1 L2 0 0 S <INNERDATA>
119
120
 *
 * Where the length of <INNERDATA> is L-3, and S is some kind of subcommand
Daniel Drake's avatar
Daniel Drake committed
121
122
 * code. L1 is the least significant bits of L, L2 is the most significant. In
 * the device's response to a command, the subcommand code will be unchanged.
123
124
125
126
127
128
129
 *
 * After deducing and documenting the above, I found a few places where the
 * above doesn't hold true. Those are marked with FIXME's below.
 */

#define CMD_SEQ_INCREMENT 0x10

Daniel Drake's avatar
Daniel Drake committed
130
static struct libusb_transfer *alloc_send_cmd_transfer(struct fp_dev *dev,
131
	unsigned char seq_a, unsigned char seq_b, const unsigned char *data,
Daniel Drake's avatar
Daniel Drake committed
132
	uint16_t len, libusb_transfer_cb_fn callback, void *user_data)
133
{
Vasily Khoruzhick's avatar
Vasily Khoruzhick committed
134
	struct libusb_transfer *transfer = libusb_alloc_transfer(0);
135
	uint16_t crc;
136
	const char *ciao = "Ciao";
137

Daniel Drake's avatar
Daniel Drake committed
138
139
	/* 9 bytes extra for: 4 byte 'Ciao', 1 byte A, 1 byte B | lenHI,
	 * 1 byte lenLO, 2 byte CRC */
140
141
142
	size_t urblen = len + 9;
	unsigned char *buf;

Daniel Drake's avatar
Daniel Drake committed
143
144
145
	if (!transfer)
		return NULL;

146
147
	if (!data && len > 0) {
		fp_err("len>0 but no data?");
Daniel Drake's avatar
Daniel Drake committed
148
		return NULL;
149
	}
Daniel Drake's avatar
Daniel Drake committed
150

151
152
153
	buf = g_malloc(urblen);

	/* Write header */
154
	memcpy(buf, ciao, strlen(ciao));
Daniel Drake's avatar
Daniel Drake committed
155
	len = GUINT16_TO_LE(len);
156
	buf[4] = seq_a;
Daniel Drake's avatar
Daniel Drake committed
157
158
	buf[5] = seq_b | ((len & 0xf00) >> 8);
	buf[6] = len & 0x00ff;
159
160
161
162
163
164

	/* Copy data */
	if (data)
		memcpy(buf + 7, data, len);

	/* Append CRC */
Daniel Drake's avatar
Daniel Drake committed
165
	crc = GUINT16_TO_BE(udf_crc(buf + 4, urblen - 6));
166
167
	buf[urblen - 2] = crc >> 8;
	buf[urblen - 1] = crc & 0xff;
Daniel Drake's avatar
Daniel Drake committed
168

169
	libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(dev), EP_OUT, buf, urblen,
Daniel Drake's avatar
Daniel Drake committed
170
171
		callback, user_data, TIMEOUT);
	return transfer;
172
173
}

Daniel Drake's avatar
Daniel Drake committed
174
175
176
static struct libusb_transfer *alloc_send_cmd28_transfer(struct fp_dev *dev,
	unsigned char subcmd, const unsigned char *data, uint16_t innerlen,
	libusb_transfer_cb_fn callback, void *user_data)
177
{
Daniel Drake's avatar
Daniel Drake committed
178
	uint16_t _innerlen = innerlen;
179
180
	size_t len = innerlen + 6;
	unsigned char *buf = g_malloc0(len);
181
	struct upekts_dev *upekdev = fpi_dev_get_user_data(dev);
182
	uint8_t seq = upekdev->seq + CMD_SEQ_INCREMENT;
Daniel Drake's avatar
Daniel Drake committed
183
	struct libusb_transfer *ret;
184
185
186

	fp_dbg("seq=%02x subcmd=%02x with %d bytes of data", seq, subcmd, innerlen);

Daniel Drake's avatar
Daniel Drake committed
187
	_innerlen = GUINT16_TO_LE(innerlen + 3);
188
	buf[0] = 0x28;
Daniel Drake's avatar
Daniel Drake committed
189
190
	buf[1] = _innerlen & 0x00ff;
	buf[2] = (_innerlen & 0xff00) >> 8;
191
192
193
	buf[5] = subcmd;
	memcpy(buf + 6, data, innerlen);

Daniel Drake's avatar
Daniel Drake committed
194
	ret = alloc_send_cmd_transfer(dev, 0, seq, buf, len, callback, user_data);
195
	upekdev->seq = seq;
196
197

	g_free(buf);
Daniel Drake's avatar
Daniel Drake committed
198
	return ret;
199
200
}

Daniel Drake's avatar
Daniel Drake committed
201
202
203
static struct libusb_transfer *alloc_send_cmdresponse_transfer(
	struct fp_dev *dev, unsigned char seq, const unsigned char *data,
	uint8_t len, libusb_transfer_cb_fn callback, void *user_data)
204
205
{
	fp_dbg("seq=%02x len=%d", seq, len);
Daniel Drake's avatar
Daniel Drake committed
206
	return alloc_send_cmd_transfer(dev, seq, 0, data, len, callback, user_data);
207
208
}

209
210
211
212
213
enum read_msg_status {
	READ_MSG_ERROR,
	READ_MSG_CMD,
	READ_MSG_RESPONSE,
};
214

215
216
217
typedef void (*read_msg_cb_fn)(struct fp_dev *dev, enum read_msg_status status,
	uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
	void *user_data);
218

219
220
221
222
223
struct read_msg_data {
	struct fp_dev *dev;
	read_msg_cb_fn callback;
	void *user_data;
};
224

225
static int __read_msg_async(struct read_msg_data *udata);
226

227
228
#define READ_MSG_DATA_CB_ERR(udata) (udata)->callback((udata)->dev, \
	READ_MSG_ERROR, 0, 0, NULL, 0, (udata)->user_data)
229

Daniel Drake's avatar
Daniel Drake committed
230
static void busy_ack_sent_cb(struct libusb_transfer *transfer)
231
{
Daniel Drake's avatar
Daniel Drake committed
232
233
234
235
	struct read_msg_data *udata = transfer->user_data;

	if (transfer->status != LIBUSB_TRANSFER_COMPLETED ||
			transfer->length != transfer->actual_length) {
236
237
238
239
		READ_MSG_DATA_CB_ERR(udata);
		g_free(udata);
	} else {
		int r = __read_msg_async(udata);
240
		if (r < 0) {
241
242
			READ_MSG_DATA_CB_ERR(udata);
			g_free(udata);
243
244
		}
	}
Daniel Drake's avatar
Daniel Drake committed
245
	libusb_free_transfer(transfer);
246
}
247

248
249
static int busy_ack_retry_read(struct read_msg_data *udata)
{
Daniel Drake's avatar
Daniel Drake committed
250
251
252
253
254
255
256
257
258
259
260
261
	struct libusb_transfer *transfer;
	int r;

	transfer = alloc_send_cmdresponse_transfer(udata->dev, 0x09, NULL, 0,
		busy_ack_sent_cb, udata);
	if (!transfer)
		return -ENOMEM;

	r = libusb_submit_transfer(transfer);
	if (r < 0) {
		g_free(transfer->buffer);
		libusb_free_transfer(transfer);
262
	}
Daniel Drake's avatar
Daniel Drake committed
263
	return r;
264
265
}

266
267
268
269
/* Returns 0 if message was handled, 1 if it was a device-busy message, and
 * negative on error. */
static int __handle_incoming_msg(struct read_msg_data *udata,
	unsigned char *buf)
270
{
271
272
273
274
275
	uint16_t len = GUINT16_FROM_LE(((buf[5] & 0xf) << 8) | buf[6]);
	uint16_t computed_crc = udf_crc(buf + 4, len + 3);
	uint16_t msg_crc = GUINT16_FROM_LE((buf[len + 8] << 8) | buf[len + 7]);
	unsigned char *retdata = NULL;
	unsigned char code_a, code_b;
276

277
278
279
280
	if (computed_crc != msg_crc) {
		fp_err("CRC failed, got %04x expected %04x", msg_crc, computed_crc);
		return -1;
	}
281
282

	code_a = buf[4];
Daniel Drake's avatar
Daniel Drake committed
283
	code_b = buf[5] & 0xf0;
Daniel Drake's avatar
Daniel Drake committed
284
	len = GUINT16_FROM_LE(((buf[5] & 0xf) << 8) | buf[6]);
285
286
287
288
289
290
291
	fp_dbg("A=%02x B=%02x len=%d", code_a, code_b, len);

	if (code_a && !code_b) {
		/* device sends command to driver */
		fp_dbg("cmd %x from device to driver", code_a);

		if (code_a == 0x08) {
292
			int r;
293
			fp_dbg("device busy, send busy-ack");
294
295
			r = busy_ack_retry_read(udata);
			return (r < 0) ? r : 1;
296
297
		}

298
299
300
		if (len > 0) {
			retdata = g_malloc(len);
			memcpy(retdata, buf + 7, len);
301
		}
302
303
304
		udata->callback(udata->dev, READ_MSG_CMD, code_a, 0, retdata, len,
			udata->user_data);
		g_free(retdata);
305
306
307
308
	} else if (!code_a) {
		/* device sends response to a previously executed command */
		unsigned char *innerbuf = buf + 7;
		unsigned char _subcmd;
Daniel Drake's avatar
Daniel Drake committed
309
		uint16_t innerlen;
310
311
312

		if (len < 6) {
			fp_err("cmd response too short (%d)", len);
313
			return -1;
314
315
316
		}
		if (innerbuf[0] != 0x28) {
			fp_err("cmd response without 28 byte?");
317
			return -1;
318
		}
319
320
321
322
323
324
325

		/* not really sure what these 2 bytes are. on most people's hardware,
		 * these bytes are always 0. However, Alon Bar-Lev's hardware gives
		 * 0xfb 0xff during the READ28_OB initsm stage. so don't error out
		 * if they are different... */
		if (innerbuf[3] || innerbuf[4])
			fp_dbg("non-zero bytes in cmd response");
326

Daniel Drake's avatar
Daniel Drake committed
327
		innerlen = innerbuf[1] | (innerbuf[2] << 8);
Daniel Drake's avatar
Daniel Drake committed
328
		innerlen = GUINT16_FROM_LE(innerlen) - 3;
329
330
		_subcmd = innerbuf[5];
		fp_dbg("device responds to subcmd %x with %d bytes", _subcmd, innerlen);
331
332
333
		if (innerlen > 0) {
			retdata = g_malloc(innerlen);
			memcpy(retdata, innerbuf + 6, innerlen);
334
		}
335
336
337
		udata->callback(udata->dev, READ_MSG_RESPONSE, code_b, _subcmd,
			retdata, innerlen, udata->user_data);
		g_free(retdata);
338
339
	} else {
		fp_err("don't know how to handle this message");
340
341
342
343
344
		return -1;
	}
	return 0;
}

Daniel Drake's avatar
Daniel Drake committed
345
static void read_msg_extend_cb(struct libusb_transfer *transfer)
346
{
Daniel Drake's avatar
Daniel Drake committed
347
348
	struct read_msg_data *udata = transfer->user_data;
	unsigned char *buf = transfer->buffer - MSG_READ_BUF_SIZE;
349
350
	int handle_result = 0;

Daniel Drake's avatar
Daniel Drake committed
351
352
	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
		fp_err("extended msg read failed, code %d", transfer->status);
353
354
		goto err;
	}
Daniel Drake's avatar
Daniel Drake committed
355
356
357
	if (transfer->actual_length < transfer->length) {
		fp_err("extended msg short read (%d/%d)", transfer->actual_length,
			transfer->length);
358
		goto err;
359
360
	}

361
362
363
364
365
366
367
	handle_result = __handle_incoming_msg(udata, buf);
	if (handle_result < 0)
		goto err;
	goto out;

err:
	READ_MSG_DATA_CB_ERR(udata);
368
out:
369
370
	if (handle_result != 1)
		g_free(udata);
371
	g_free(buf);
Daniel Drake's avatar
Daniel Drake committed
372
	libusb_free_transfer(transfer);
373
374
}

Daniel Drake's avatar
Daniel Drake committed
375
static void read_msg_cb(struct libusb_transfer *transfer)
376
{
Daniel Drake's avatar
Daniel Drake committed
377
378
	struct read_msg_data *udata = transfer->user_data;
	unsigned char *data = transfer->buffer;
379
380
	uint16_t len;
	int handle_result = 0;
381

Daniel Drake's avatar
Daniel Drake committed
382
383
	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
		fp_err("async msg read failed, code %d", transfer->status);
384
		goto err;
385
	}
Daniel Drake's avatar
Daniel Drake committed
386
387
	if (transfer->actual_length < 9) {
		fp_err("async msg read too short (%d)", transfer->actual_length);
388
		goto err;
389
	}
390
391
392
393

	if (strncmp(data, "Ciao", 4) != 0) {
		fp_err("no Ciao for you!!");
		goto err;
394
395
	}

396
	len = GUINT16_FROM_LE(((data[5] & 0xf) << 8) | data[6]);
Daniel Drake's avatar
Daniel Drake committed
397
398
	if (transfer->actual_length != MSG_READ_BUF_SIZE
			&& (len + 9) > transfer->actual_length) {
399
400
401
		/* Check that the length claimed inside the message is in line with
		 * the amount of data that was transferred over USB. */
		fp_err("msg didn't include enough data, expected=%d recv=%d",
Daniel Drake's avatar
Daniel Drake committed
402
			len + 9, transfer->actual_length);
403
404
405
406
407
408
409
410
		goto err;
	}

	/* We use a 64 byte buffer for reading messages. However, sometimes
	 * messages are longer, in which case we have to do another USB bulk read
	 * to read the remainder. This is handled below. */
	if (len > MAX_DATA_IN_READ_BUF) {
		int needed = len - MAX_DATA_IN_READ_BUF;
Vasily Khoruzhick's avatar
Vasily Khoruzhick committed
411
		struct libusb_transfer *etransfer = libusb_alloc_transfer(0);
Daniel Drake's avatar
Daniel Drake committed
412
413
414
415
		int r;

		if (!transfer)
			goto err;
416
417
418

		fp_dbg("didn't fit in buffer, need to extend by %d bytes", needed);
		data = g_realloc((gpointer) data, MSG_READ_BUF_SIZE + needed);
Daniel Drake's avatar
Daniel Drake committed
419

420
		libusb_fill_bulk_transfer(etransfer, fpi_dev_get_usb_dev(udata->dev), EP_IN,
Daniel Drake's avatar
Daniel Drake committed
421
422
423
424
425
			data + MSG_READ_BUF_SIZE, needed, read_msg_extend_cb, udata,
			TIMEOUT);

		r = libusb_submit_transfer(etransfer);
		if (r < 0) {
426
			fp_err("extended read submission failed");
Daniel Drake's avatar
Daniel Drake committed
427
			/* FIXME memory leak here? */
428
429
			goto err;
		}
Daniel Drake's avatar
Daniel Drake committed
430
		libusb_free_transfer(transfer);
431
432
433
434
435
436
437
438
439
440
441
		return;
	}

	handle_result = __handle_incoming_msg(udata, data);
	if (handle_result < 0)
		goto err;
	goto out;

err:
	READ_MSG_DATA_CB_ERR(udata);
out:
Daniel Drake's avatar
Daniel Drake committed
442
	libusb_free_transfer(transfer);
443
444
445
446
447
448
449
450
	if (handle_result != 1)
		g_free(udata);
	g_free(data);
}

static int __read_msg_async(struct read_msg_data *udata)
{
	unsigned char *buf = g_malloc(MSG_READ_BUF_SIZE);
Vasily Khoruzhick's avatar
Vasily Khoruzhick committed
451
	struct libusb_transfer *transfer = libusb_alloc_transfer(0);
Daniel Drake's avatar
Daniel Drake committed
452
453
454
	int r;

	if (!transfer) {
455
		g_free(buf);
Daniel Drake's avatar
Daniel Drake committed
456
		return -ENOMEM;
457
	}
Daniel Drake's avatar
Daniel Drake committed
458

459
	libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(udata->dev), EP_IN, buf,
Daniel Drake's avatar
Daniel Drake committed
460
461
462
463
464
465
466
467
		MSG_READ_BUF_SIZE, read_msg_cb, udata, TIMEOUT);
	r = libusb_submit_transfer(transfer);
	if (r < 0) {
		g_free(buf);
		libusb_free_transfer(transfer);
	}

	return r;
468
469
}

470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
static int read_msg_async(struct fp_dev *dev, read_msg_cb_fn callback,
	void *user_data)
{
	struct read_msg_data *udata = g_malloc(sizeof(*udata));
	int r;

	udata->dev = dev;
	udata->callback = callback;
	udata->user_data = user_data;
	r = __read_msg_async(udata);
	if (r)
		g_free(udata);
	return r;
}

485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
static const unsigned char init_resp03[] = {
	0x01, 0x00, 0xe8, 0x03, 0x00, 0x00, 0xff, 0x07
};
static const unsigned char init28_08[] = {
	0x04, 0x83, 0x00, 0x2c, 0x22, 0x23, 0x97, 0xc9, 0xa7, 0x15, 0xa0, 0x8a,
	0xab, 0x3c, 0xd0, 0xbf, 0xdb, 0xf3, 0x92, 0x6f, 0xae, 0x3b, 0x1e, 0x44,
	0xc4
};
static const unsigned char init28_0c[] = {
	0x04, 0x03, 0x00, 0x00, 0x00
};
static const unsigned char init28_0b[] = {
	0x04, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
	0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a,
	0x00, 0x64, 0x00, 0xf4, 0x01, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00
};

508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
/* device initialisation state machine */

enum initsm_states {
	WRITE_CTRL400 = 0,
	READ_MSG03,
	SEND_RESP03,
	READ_MSG05,
	SEND28_06,
	READ28_06,
	SEND28_07,
	READ28_07,
	SEND28_08,
	READ28_08,
	SEND28_0C,
	READ28_0C,
	SEND28_0B,
	READ28_0B,
	INITSM_NUM_STATES,
};
527

528
529
530
531
static void initsm_read_msg_response_cb(struct fpi_ssm *ssm,
	enum read_msg_status status, uint8_t seq,
	unsigned char expect_subcmd, unsigned char subcmd)
{
532
	struct fp_dev *dev = fpi_ssm_get_dev(ssm);
533
	struct upekts_dev *upekdev = fpi_dev_get_user_data(dev);
534

535
536
	if (status != READ_MSG_RESPONSE) {
		fp_err("expected response, got %d seq=%x in state %d", status, seq,
537
			fpi_ssm_get_cur_state(ssm));
538
539
540
		fpi_ssm_mark_aborted(ssm, -1);
	} else if (subcmd != expect_subcmd) {
		fp_warn("expected response to subcmd 0x%02x, got response to %02x in "
541
			"state %d", expect_subcmd, subcmd, fpi_ssm_get_cur_state(ssm));
542
543
544
		fpi_ssm_mark_aborted(ssm, -1);
	} else if (seq != upekdev->seq) {
		fp_err("expected response to cmd seq=%02x, got response to %02x "
545
			"in state %d", upekdev->seq, seq, fpi_ssm_get_cur_state(ssm));
546
547
		fpi_ssm_mark_aborted(ssm, -1);
	} else {
548
		fp_dbg("state %d completed", fpi_ssm_get_cur_state(ssm));
549
		fpi_ssm_next_state(ssm);
550
	}
551
}
552

553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
static void read28_0b_cb(struct fp_dev *dev, enum read_msg_status status,
	uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
	void *user_data)
{
	initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
		0x0b, subcmd);
}

static void read28_0c_cb(struct fp_dev *dev, enum read_msg_status status,
	uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
	void *user_data)
{
	initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
		0x0c, subcmd);
}

static void read28_08_cb(struct fp_dev *dev, enum read_msg_status status,
	uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
	void *user_data)
{
	initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
		0x08, subcmd);
}

static void read28_07_cb(struct fp_dev *dev, enum read_msg_status status,
	uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
	void *user_data)
{
	initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
		0x07, subcmd);
}

static void read28_06_cb(struct fp_dev *dev, enum read_msg_status status,
	uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
	void *user_data)
{
	initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
		0x06, subcmd);
}

static void initsm_read_msg_cmd_cb(struct fpi_ssm *ssm,
	enum read_msg_status status, uint8_t expect_seq, uint8_t seq)
{
596
	struct fp_dev *dev = fpi_ssm_get_dev(ssm);
597
	struct upekts_dev *upekdev = fpi_dev_get_user_data(dev);
598
599
600
601
602
603

	if (status == READ_MSG_ERROR) {
		fpi_ssm_mark_aborted(ssm, -1);
		return;
	} else if (status != READ_MSG_CMD) {
		fp_err("expected command, got %d seq=%x in state %d", status, seq,
604
			fpi_ssm_get_cur_state(ssm));
605
606
		fpi_ssm_mark_aborted(ssm, -1);
		return;
607
	}
608
609
610
	upekdev->seq = seq;
	if (seq != expect_seq) {
		fp_err("expected seq=%x, got %x in state %d", expect_seq, seq,
611
			fpi_ssm_get_cur_state(ssm));
612
613
		fpi_ssm_mark_aborted(ssm, -1);
		return;
614
615
	}

616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
	fpi_ssm_next_state(ssm);
}

static void read_msg05_cb(struct fp_dev *dev, enum read_msg_status status,
	uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
	void *user_data)
{
	initsm_read_msg_cmd_cb((struct fpi_ssm *) user_data, status, 5, seq); 
}

static void read_msg03_cb(struct fp_dev *dev, enum read_msg_status status,
	uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
	void *user_data)
{
	initsm_read_msg_cmd_cb((struct fpi_ssm *) user_data, status, 3, seq); 
}

Daniel Drake's avatar
Daniel Drake committed
633
static void ctrl400_cb(struct libusb_transfer *transfer)
634
{
Daniel Drake's avatar
Daniel Drake committed
635
636
637
	struct fpi_ssm *ssm = transfer->user_data;
	/* FIXME check length? */
	if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
638
639
640
		fpi_ssm_next_state(ssm);
	else
		fpi_ssm_mark_aborted(ssm, -1);
Daniel Drake's avatar
Daniel Drake committed
641
642
	g_free(transfer->buffer);
	libusb_free_transfer(transfer);
643
644
645
646
647
}

static void initsm_read_msg_handler(struct fpi_ssm *ssm,
	read_msg_cb_fn callback)
{
648
	int r = read_msg_async(fpi_ssm_get_dev(ssm), callback, ssm);
649
	if (r < 0) {
650
		fp_err("async read msg failed in state %d", fpi_ssm_get_cur_state(ssm));
651
		fpi_ssm_mark_aborted(ssm, r);
652
	}
653
654
}

Daniel Drake's avatar
Daniel Drake committed
655
static void initsm_send_msg_cb(struct libusb_transfer *transfer)
656
{
Daniel Drake's avatar
Daniel Drake committed
657
658
659
	struct fpi_ssm *ssm = transfer->user_data;
	if (transfer->status == LIBUSB_TRANSFER_COMPLETED
			&& transfer->length == transfer->actual_length) {
660
		fp_dbg("state %d completed", fpi_ssm_get_cur_state(ssm));
661
662
		fpi_ssm_next_state(ssm);
	} else {
663
		fp_err("failed, state=%d rqlength=%d actual_length=%d", fpi_ssm_get_cur_state(ssm),
Daniel Drake's avatar
Daniel Drake committed
664
			transfer->length, transfer->actual_length);
665
		fpi_ssm_mark_aborted(ssm, -1);
666
	}
Daniel Drake's avatar
Daniel Drake committed
667
	libusb_free_transfer(transfer);
668
}
669

670
671
672
static void initsm_send_msg28_handler(struct fpi_ssm *ssm,
	unsigned char subcmd, const unsigned char *data, uint16_t innerlen)
{
673
	struct fp_dev *dev = fpi_ssm_get_dev(ssm);
Daniel Drake's avatar
Daniel Drake committed
674
675
676
677
678
679
680
681
682
683
684
685
	struct libusb_transfer *transfer;
	int r;

	transfer = alloc_send_cmd28_transfer(dev, subcmd, data, innerlen,
		initsm_send_msg_cb, ssm);
	if (!transfer) {
		fpi_ssm_mark_aborted(ssm, -ENOMEM);
		return;
	}

	r = libusb_submit_transfer(transfer);
	if (r < 0) {
686
		fp_err("urb submission failed error %d in state %d", r, fpi_ssm_get_cur_state(ssm));
Daniel Drake's avatar
Daniel Drake committed
687
688
		g_free(transfer->buffer);
		libusb_free_transfer(transfer);
689
690
691
		fpi_ssm_mark_aborted(ssm, -EIO);
	}
}
692

693
694
static void initsm_run_state(struct fpi_ssm *ssm)
{
695
	struct fp_dev *dev = fpi_ssm_get_dev(ssm);
696
	struct upekts_dev *upekdev = fpi_dev_get_user_data(dev);
Daniel Drake's avatar
Daniel Drake committed
697
698
	struct libusb_transfer *transfer;
	int r;
699

700
	switch (fpi_ssm_get_cur_state(ssm)) {
701
	case WRITE_CTRL400: ;
Daniel Drake's avatar
Daniel Drake committed
702
703
		unsigned char *data;

Vasily Khoruzhick's avatar
Vasily Khoruzhick committed
704
		transfer = libusb_alloc_transfer(0);
Daniel Drake's avatar
Daniel Drake committed
705
706
707
708
709
710
711
		if (!transfer) {
			fpi_ssm_mark_aborted(ssm, -ENOMEM);
			break;
		}
		
		data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
		libusb_fill_control_setup(data,
712
			LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 0x0c, 0x100, 0x0400, 1);
713
		libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(dev), data,
714
			ctrl400_cb, ssm, TIMEOUT);
Daniel Drake's avatar
Daniel Drake committed
715
716
717
718
719
720
721

		r = libusb_submit_transfer(transfer);
		if (r < 0) {
			g_free(data);
			libusb_free_transfer(transfer);
			fpi_ssm_mark_aborted(ssm, r);
		}
722
723
724
725
726
		break;
	case READ_MSG03:
		initsm_read_msg_handler(ssm, read_msg03_cb);
		break;
	case SEND_RESP03: ;
Daniel Drake's avatar
Daniel Drake committed
727
728
729
730
731
732
733
734
735
736
737
738
		transfer = alloc_send_cmdresponse_transfer(dev, ++upekdev->seq,
			init_resp03, sizeof(init_resp03), initsm_send_msg_cb, ssm);
		if (!transfer) {
			fpi_ssm_mark_aborted(ssm, -ENOMEM);
			break;
		}

		r = libusb_submit_transfer(transfer);
		if (r < 0) {
			g_free(transfer->buffer);
			libusb_free_transfer(transfer);
			fpi_ssm_mark_aborted(ssm, r);
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
		}
		break;
	case READ_MSG05:
		initsm_read_msg_handler(ssm, read_msg05_cb);
		break;
	case SEND28_06: ;
		unsigned char dummy28_06 = 0x04;
		upekdev->seq = 0xf0;
		initsm_send_msg28_handler(ssm, 0x06, &dummy28_06, 1);
		break;
	case READ28_06:
		initsm_read_msg_handler(ssm, read28_06_cb);
		break;
	case SEND28_07: ;
		unsigned char dummy28_07 = 0x04;
		initsm_send_msg28_handler(ssm, 0x07, &dummy28_07, 1);
		break;
	case READ28_07:
		initsm_read_msg_handler(ssm, read28_07_cb);
		break;
	case SEND28_08:
		initsm_send_msg28_handler(ssm, 0x08, init28_08, sizeof(init28_08));
		break;
	case READ28_08:
		initsm_read_msg_handler(ssm, read28_08_cb);
		break;
	case SEND28_0C:
		initsm_send_msg28_handler(ssm, 0x0c, init28_0c, sizeof(init28_0c));
		break;
	case READ28_0C:
		initsm_read_msg_handler(ssm, read28_0c_cb);
		break;
	case SEND28_0B:
		initsm_send_msg28_handler(ssm, 0x0b, init28_0b, sizeof(init28_0b));
		break;
	case READ28_0B:
		initsm_read_msg_handler(ssm, read28_0b_cb);
		break;
	}
}
779

780
781
782
783
static struct fpi_ssm *initsm_new(struct fp_dev *dev)
{
	return fpi_ssm_new(dev, initsm_run_state, INITSM_NUM_STATES);
}
784

785
786
787
788
789
enum deinitsm_states {
	SEND_RESP07 = 0,
	READ_MSG01,
	DEINITSM_NUM_STATES,
};
790

Daniel Drake's avatar
Daniel Drake committed
791
static void send_resp07_cb(struct libusb_transfer *transfer)
792
{
Daniel Drake's avatar
Daniel Drake committed
793
794
	struct fpi_ssm *ssm = transfer->user_data;
	if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
795
		fpi_ssm_mark_aborted(ssm, -EIO);
Daniel Drake's avatar
Daniel Drake committed
796
	else if (transfer->length != transfer->actual_length)
797
798
799
		fpi_ssm_mark_aborted(ssm, -EPROTO);
	else
		fpi_ssm_next_state(ssm);
Daniel Drake's avatar
Daniel Drake committed
800
	libusb_free_transfer(transfer);
801
802
}

803
804
805
static void read_msg01_cb(struct fp_dev *dev, enum read_msg_status status,
	uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
	void *user_data)
806
{
807
	struct fpi_ssm *ssm = user_data;
808
	struct upekts_dev *upekdev = fpi_dev_get_user_data(dev);
809

810
811
812
813
814
815
816
	if (status == READ_MSG_ERROR) {
		fpi_ssm_mark_aborted(ssm, -1);
		return;
	} else if (status != READ_MSG_CMD) {
		fp_err("expected command, got %d seq=%x", status, seq);
		fpi_ssm_mark_aborted(ssm, -1);
		return;
817
	}
818
	upekdev->seq = seq;
819
820
	if (seq != 1) {
		fp_err("expected seq=1, got %x", seq);
821
822
		fpi_ssm_mark_aborted(ssm, -1);
		return;
823
824
	}

825
826
827
828
829
	fpi_ssm_next_state(ssm);
}

static void deinitsm_state_handler(struct fpi_ssm *ssm)
{
830
	struct fp_dev *dev = fpi_ssm_get_dev(ssm);
Daniel Drake's avatar
Daniel Drake committed
831
	int r;
832

833
	switch (fpi_ssm_get_cur_state(ssm)) {
834
	case SEND_RESP07: ;
Daniel Drake's avatar
Daniel Drake committed
835
		struct libusb_transfer *transfer;
836
837
		unsigned char dummy = 0;

Daniel Drake's avatar
Daniel Drake committed
838
839
840
841
842
843
844
845
846
847
848
849
		transfer = alloc_send_cmdresponse_transfer(dev, 0x07, &dummy, 1,
			send_resp07_cb, ssm);
		if (!transfer) {
			fpi_ssm_mark_aborted(ssm, -ENOMEM);
			break;
		}

		r = libusb_submit_transfer(transfer);
		if (r < 0) {
			g_free(transfer->buffer);
			libusb_free_transfer(transfer);
			fpi_ssm_mark_aborted(ssm, r);
850
851
852
		}
		break;
	case READ_MSG01: ;
Daniel Drake's avatar
Daniel Drake committed
853
		r = read_msg_async(dev, read_msg01_cb, ssm);
854
855
856
857
858
859
860
861
862
		if (r < 0)
			fpi_ssm_mark_aborted(ssm, r);
		break;
	}
}

static struct fpi_ssm *deinitsm_new(struct fp_dev *dev)
{
	return fpi_ssm_new(dev, deinitsm_state_handler, DEINITSM_NUM_STATES);
863
864
865
866
867
868
869
}

static int dev_init(struct fp_dev *dev, unsigned long driver_data)
{
	struct upekts_dev *upekdev = NULL;
	int r;

870
	r = libusb_claim_interface(fpi_dev_get_usb_dev(dev), 0);
871
872
	if (r < 0) {
		fp_err("could not claim interface 0: %s", libusb_error_name(r));
873
		return r;
874
	}
875
876
877

	upekdev = g_malloc(sizeof(*upekdev));
	upekdev->seq = 0xf0; /* incremented to 0x00 before first cmd */
878
879
	fpi_dev_set_user_data(dev, upekdev);
	fpi_dev_set_nr_enroll_stages(dev, 3);
880

Daniel Drake's avatar
Daniel Drake committed
881
	fpi_drvcb_open_complete(dev, 0);
882
883
884
885
886
	return 0;
}

static void dev_exit(struct fp_dev *dev)
{
887
888
889
890
	void *user_data;
	libusb_release_interface(fpi_dev_get_usb_dev(dev), 0);
	user_data = fpi_dev_get_user_data(dev);
	g_free(user_data);
Daniel Drake's avatar
Daniel Drake committed
891
	fpi_drvcb_close_complete(dev);
892
893
894
895
896
897
898
899
900
}

static const unsigned char enroll_init[] = {
	0x02, 0xc0, 0xd4, 0x01, 0x00, 0x04, 0x00, 0x08
};
static const unsigned char scan_comp[] = {
	0x12, 0xff, 0xff, 0xff, 0xff /* scan completion, prefixes print data */
};

Daniel Drake's avatar
Daniel Drake committed
901
902
903
/* used for enrollment and verification */
static const unsigned char poll_data[] = { 0x30, 0x01 };

904
905
906
907
908
909
910
911
912
enum enroll_start_sm_states {
	RUN_INITSM = 0,
	ENROLL_INIT,
	READ_ENROLL_MSG28,
	ENROLL_START_NUM_STATES,
};

/* Called when the device initialization state machine completes */
static void enroll_start_sm_cb_initsm(struct fpi_ssm *initsm)
913
{
914
915
	struct fpi_ssm *enroll_start_ssm = fpi_ssm_get_user_data(initsm);
	int error = fpi_ssm_get_error(initsm);
916
917
918
919
920
921
922

	fpi_ssm_free(initsm);
	if (error)
		fpi_ssm_mark_aborted(enroll_start_ssm, error);
	else
		fpi_ssm_next_state(enroll_start_ssm);
}
923

924
/* called when enroll init URB has completed */
Daniel Drake's avatar
Daniel Drake committed
925
static void enroll_start_sm_cb_init(struct libusb_transfer *transfer)
926
{
Daniel Drake's avatar
Daniel Drake committed
927
928
	struct fpi_ssm *ssm = transfer->user_data;
	if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
929
		fpi_ssm_mark_aborted(ssm, -EIO);
Daniel Drake's avatar
Daniel Drake committed
930
	else if (transfer->length != transfer->actual_length)
931
932
933
		fpi_ssm_mark_aborted(ssm, -EPROTO);
	else
		fpi_ssm_next_state(ssm);
Daniel Drake's avatar
Daniel Drake committed
934
	libusb_free_transfer(transfer);
935
}
936

937
938
939
940
static void enroll_start_sm_cb_msg28(struct fp_dev *dev,
	enum read_msg_status status, uint8_t seq, unsigned char subcmd,
	unsigned char *data, size_t data_len, void *user_data)
{
941
	struct upekts_dev *upekdev = fpi_dev_get_user_data(dev);
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
	struct fpi_ssm *ssm = user_data;

	if (status != READ_MSG_RESPONSE) {
		fp_err("expected response, got %d seq=%x", status, seq);
		fpi_ssm_mark_aborted(ssm, -1);
	} else if (subcmd != 0) {
		fp_warn("expected response to subcmd 0, got response to %02x",
			subcmd);
		fpi_ssm_mark_aborted(ssm, -1);
	} else if (seq != upekdev->seq) {
		fp_err("expected response to cmd seq=%02x, got response to %02x",
			upekdev->seq, seq);
		fpi_ssm_mark_aborted(ssm, -1);
	} else {
		fpi_ssm_next_state(ssm);
	}
}

static void enroll_start_sm_run_state(struct fpi_ssm *ssm)
{
962
	struct fp_dev *dev = fpi_ssm_get_dev(ssm);
Daniel Drake's avatar
Daniel Drake committed
963
	int r;
964

965
	switch (fpi_ssm_get_cur_state(ssm)) {
966
967
	case RUN_INITSM: ;
		struct fpi_ssm *initsm = initsm_new(dev);
968
		fpi_ssm_set_user_data(initsm, ssm);
969
970
971
		fpi_ssm_start(initsm, enroll_start_sm_cb_initsm);
		break;
	case ENROLL_INIT: ;
Daniel Drake's avatar
Daniel Drake committed
972
973
974
975
976
977
978
979
980
981
982
983
984
		struct libusb_transfer *transfer;
		transfer = alloc_send_cmd28_transfer(dev, 0x02, enroll_init,
			sizeof(enroll_init), enroll_start_sm_cb_init, ssm);
		if (!transfer) {
			fpi_ssm_mark_aborted(ssm, -ENOMEM);
			break;
		}

		r = libusb_submit_transfer(transfer);
		if (r < 0) {
			g_free(transfer->buffer);
			libusb_free_transfer(transfer);
			fpi_ssm_mark_aborted(ssm, r);
985
986
987
		}
		break;
	case READ_ENROLL_MSG28: ;
988
989
		/* FIXME: protocol misunderstanding here. device receives response
		 * to subcmd 0 after submitting subcmd 2? */
Daniel Drake's avatar
Daniel Drake committed
990
991
		/* actually this is probably a poll response? does the above cmd
		 * include a 30 01 poll somewhere? */
Daniel Drake's avatar
Daniel Drake committed
992
		r = read_msg_async(dev, enroll_start_sm_cb_msg28, ssm);
993
994
995
		if (r < 0)
			fpi_ssm_mark_aborted(ssm, r);
		break;
996
	}
997
}
998

999
static void enroll_iterate(struct fp_dev *dev);
1000

1001
1002
1003
static void e_handle_resp00(struct fp_dev *dev, unsigned char *data,
	size_t data_len)
{
1004
	struct upekts_dev *upekdev = fpi_dev_get_user_data(dev);
1005
1006
	unsigned char status;
	int result = 0;
1007

1008
	if (data_len != 14) {
1009
		fp_err("received 3001 poll response of %lu bytes?", data_len);
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
		fpi_drvcb_enroll_stage_completed(dev, -EPROTO, NULL, NULL);
		return;
	}

	status = data[5];
	fp_dbg("poll result = %02x", status);

	switch (status) {
	case 0x0c:
	case 0x0d:
	case 0x0e:
		/* if we previously completed a non-last enrollment stage, we'll
		 * get this code to indicate successful stage completion */
		if (upekdev->enroll_passed) {
			result = FP_ENROLL_PASS;
			upekdev->enroll_passed = FALSE;
1026
		}
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
		/* otherwise it just means "no news" so we poll again */
		break;
	case 0x1c: /* FIXME what does this one mean? */
	case 0x0b: /* FIXME what does this one mean? */
	case 0x23: /* FIXME what does this one mean? */
		result = FP_ENROLL_RETRY;
		break;
	case 0x0f: /* scan taking too long, remove finger and try again */
		result = FP_ENROLL_RETRY_REMOVE_FINGER;
		break;
	case 0x1e: /* swipe too short */
		result = FP_ENROLL_RETRY_TOO_SHORT;
		break;
	case 0x24: /* finger not centered */
		result = FP_ENROLL_RETRY_CENTER_FINGER;
		break;
	case 0x20:
		/* finger scanned successfully */
		/* need to look at the next poll result to determine if enrollment is
		 * complete or not */
		upekdev->enroll_passed = 1;
		break;
	case 0x00: /* enrollment complete */
		/* we can now expect the enrollment data on the next poll, so we
		 * have nothing to do here */
		break;
	default:
		fp_err("unrecognised scan status code %02x", status);
		result = -EPROTO;
		break;
	}

	if (result) {
		fpi_drvcb_enroll_stage_completed(dev, result, NULL, NULL);
		if (result > 0)
			enroll_iterate(dev);
	} else {
		enroll_iterate(dev);
1065
1066
1067
1068
	}

	/* FIXME: need to extend protocol research to handle the case when
	 * enrolment fails, e.g. you scan a different finger on each stage */
1069
1070
1071
	/* FIXME: should do proper tracking of when we expect cmd0 results and
	 * cmd2 results and enforce it */
}
1072

1073
1074
1075
1076
static void e_handle_resp02(struct fp_dev *dev, unsigned char *data,
	size_t data_len)
{
	struct fp_print_data *fdata = NULL;
1077
	struct fp_print_data_item *item = NULL;
1078
1079
1080
	int result = -EPROTO;

	if (data_len < sizeof(scan_comp)) {
1081
		fp_err("fingerprint data too short (%lu bytes)", data_len);
1082
1083
1084
1085
	} else if (memcmp(data, scan_comp, sizeof(scan_comp)) != 0) {
		fp_err("unrecognised data prefix %x %x %x %x %x",
			data[0], data[1], data[2], data[3], data[4]);
	} else {
1086
1087
1088
		fdata = fpi_print_data_new(dev);
		item = fpi_print_data_item_new(data_len - sizeof(scan_comp));
		memcpy(item->data, data + sizeof(scan_comp),
1089
			data_len - sizeof(scan_comp));
1090
		fdata->prints = g_slist_prepend(fdata->prints, item);
1091

1092
1093
		result = FP_ENROLL_COMPLETE;
	}
1094

1095
1096
	fpi_drvcb_enroll_stage_completed(dev, result, fdata, NULL);
}
1097

1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
static void enroll_iterate_msg_cb(struct fp_dev *dev,
	enum read_msg_status msgstat, uint8_t seq, unsigned char subcmd,
	unsigned char *data, size_t data_len, void *user_data)
{
	if (msgstat != READ_MSG_RESPONSE) {
		fp_err("expected response, got %d seq=%x", msgstat, seq);
		fpi_drvcb_enroll_stage_completed(dev, -EPROTO, NULL, NULL);
		return;
	}
	if (subcmd == 0) {
		e_handle_resp00(dev, data, data_len);
	} else if (subcmd == 2) {
		e_handle_resp02(dev, data, data_len);
	} else {
		fp_err("unexpected subcmd %d", subcmd);
		fpi_drvcb_enroll_stage_completed(dev, -EPROTO, NULL, NULL);
1114
1115
	}

1116
1117
}

Daniel Drake's avatar
Daniel Drake committed
1118
static void enroll_iterate_cmd_cb(struct libusb_transfer *transfer)
1119
{
Daniel Drake's avatar
Daniel Drake committed
1120
	struct fp_dev *dev = transfer->user_data;
1121

Daniel Drake's avatar
Daniel Drake committed
1122
	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
1123
		fpi_drvcb_enroll_stage_completed(dev, -EIO, NULL, NULL);
Daniel Drake's avatar
Daniel Drake committed
1124
	} else if (transfer->length != transfer->actual_length) {
1125
1126
1127
1128
1129
1130
		fpi_drvcb_enroll_stage_completed(dev, -EPROTO, NULL, NULL);
	} else {
		int r = read_msg_async(dev, enroll_iterate_msg_cb, NULL);
		if (r < 0)
			fpi_drvcb_enroll_stage_completed(dev, r, NULL, NULL);
	}
Daniel Drake's avatar
Daniel Drake committed
1131
	libusb_free_transfer(transfer);
1132
1133
1134
1135
}

static void enroll_iterate(struct fp_dev *dev)
{
Daniel Drake's avatar
Daniel Drake committed
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
	int r;
	struct libusb_transfer *transfer = alloc_send_cmd28_transfer(dev, 0x00,
		poll_data, sizeof(poll_data), enroll_iterate_cmd_cb, dev);

	if (!transfer) {
		fpi_drvcb_enroll_stage_completed(dev, -ENOMEM, NULL, NULL);
		return;
	}

	r = libusb_submit_transfer(transfer);
	if (r < 0) {
		g_free(transfer->buffer);
		libusb_free_transfer(transfer);
1149
1150
1151
1152
1153
1154
		fpi_drvcb_enroll_stage_completed(dev, -EIO, NULL, NULL);
	}
}

static void enroll_started(struct fpi_ssm *ssm)
{
1155
1156
	struct fp_dev *dev = fpi_ssm_get_dev(ssm);
	fpi_drvcb_enroll_started(dev, fpi_ssm_get_error(ssm));
1157

1158
	if (!fpi_ssm_get_error(ssm))
1159
1160
1161
1162
1163
1164
1165
		enroll_iterate(dev);

	fpi_ssm_free(ssm);
}

static int enroll_start(struct fp_dev *dev)
{