uru4000.c 37.3 KB
Newer Older
Daniel Drake's avatar
Daniel Drake committed
1
/*
2
 * Digital Persona U.are.U 4000/4000B/4500 driver for libfprint
3
 * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
4
 * Copyright (C) 2012 Timo Teräs <timo.teras@iki.fi>
Daniel Drake's avatar
Daniel Drake committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * 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; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * 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
 */

#define FP_COMPONENT "uru4000"

23 24
#include <nss.h>
#include <pk11pub.h>
Daniel Drake's avatar
Daniel Drake committed
25

26
#include "drivers_api.h"
27

28 29
#define EP_INTR			(1 | LIBUSB_ENDPOINT_IN)
#define EP_DATA			(2 | LIBUSB_ENDPOINT_IN)
Daniel Drake's avatar
Daniel Drake committed
30
#define USB_RQ			0x04
31 32
#define CTRL_IN			(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)
#define CTRL_OUT		(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT)
33 34
#define CTRL_TIMEOUT		5000
#define BULK_TIMEOUT		5000
Daniel Drake's avatar
Daniel Drake committed
35
#define IRQ_LENGTH		64
36
#define CR_LENGTH		16
Daniel Drake's avatar
Daniel Drake committed
37

38 39 40
#define IMAGE_HEIGHT		290
#define IMAGE_WIDTH		384

41
#define ENC_THRESHOLD		5000
42

Daniel Drake's avatar
Daniel Drake committed
43 44 45 46
enum {
	IRQDATA_SCANPWR_ON = 0x56aa,
	IRQDATA_FINGER_ON = 0x0101,
	IRQDATA_FINGER_OFF = 0x0200,
47
	IRQDATA_DEATH = 0x0800,
Daniel Drake's avatar
Daniel Drake committed
48 49 50 51
};

enum {
	REG_HWSTAT = 0x07,
52 53
	REG_SCRAMBLE_DATA_INDEX = 0x33,
	REG_SCRAMBLE_DATA_KEY = 0x34,
Daniel Drake's avatar
Daniel Drake committed
54
	REG_MODE = 0x4e,
55
	REG_DEVICE_INFO = 0xf0,
56
	/* firmware starts at 0x100 */
57 58
	REG_RESPONSE = 0x2000,
	REG_CHALLENGE = 0x2010,
Daniel Drake's avatar
Daniel Drake committed
59 60 61 62 63 64 65
};

enum {
	MODE_INIT = 0x00,
	MODE_AWAIT_FINGER_ON = 0x10,
	MODE_AWAIT_FINGER_OFF = 0x12,
	MODE_CAPTURE = 0x20,
66 67
	MODE_CAPTURE_AUX = 0x30,
	MODE_OFF = 0x70,
Daniel Drake's avatar
Daniel Drake committed
68 69 70 71 72 73 74 75 76 77 78 79 80 81
	MODE_READY = 0x80,
};

enum {
	MS_KBD,
	MS_INTELLIMOUSE,
	MS_STANDALONE,
	MS_STANDALONE_V2,
	DP_URU4000,
	DP_URU4000B,
};

static const struct uru4k_dev_profile {
	const char *name;
82
	gboolean auth_cr;
83
	gboolean encryption;
Daniel Drake's avatar
Daniel Drake committed
84 85 86
} uru4k_dev_info[] = {
	[MS_KBD] = {
		.name = "Microsoft Keyboard with Fingerprint Reader",
87
		.auth_cr = FALSE,
Daniel Drake's avatar
Daniel Drake committed
88 89 90
	},
	[MS_INTELLIMOUSE] = {
		.name = "Microsoft Wireless IntelliMouse with Fingerprint Reader",
91
		.auth_cr = FALSE,
Daniel Drake's avatar
Daniel Drake committed
92 93 94
	},
	[MS_STANDALONE] = {
		.name = "Microsoft Fingerprint Reader",
95 96 97 98
		.auth_cr = FALSE,
	},
	[MS_STANDALONE_V2] = {
		.name = "Microsoft Fingerprint Reader v2",
99
		.auth_cr = TRUE,
100 101 102
	},
	[DP_URU4000] = {
		.name = "Digital Persona U.are.U 4000",
103
		.auth_cr = FALSE,
Daniel Drake's avatar
Daniel Drake committed
104 105 106
	},
	[DP_URU4000B] = {
		.name = "Digital Persona U.are.U 4000B",
107
		.auth_cr = FALSE,
108
		.encryption = TRUE,
Daniel Drake's avatar
Daniel Drake committed
109 110 111
	},
};

112 113 114 115
typedef void (*irq_cb_fn)(struct fp_img_dev *dev, int status, uint16_t type,
	void *user_data);
typedef void (*irqs_stopped_cb_fn)(struct fp_img_dev *dev);

Daniel Drake's avatar
Daniel Drake committed
116
struct uru4k_dev {
117
	const struct uru4k_dev_profile *profile;
Daniel Drake's avatar
Daniel Drake committed
118
	uint8_t interface;
119
	enum fp_imgdev_state activate_state;
120
	unsigned char last_reg_rd[16];
121
	unsigned char last_hwstat;
122

123 124
	fpi_usb_transfer *irq_transfer;
	fpi_usb_transfer *img_transfer;
125
	void *img_data;
126
	int img_data_actual_length;
127 128
	uint16_t img_lines_done, img_block;
	uint32_t img_enc_seed;
129 130 131 132 133 134 135 136 137

	irq_cb_fn irq_cb;
	void *irq_cb_data;
	irqs_stopped_cb_fn irqs_stopped_cb;

	int rebootpwr_ctr;
	int powerup_ctr;
	unsigned char powerup_hwstat;

138
	int scanpwr_irq_timeouts;
139
	fpi_timeout *scanpwr_irq_timeout;
140

141 142 143
	int fwfixer_offset;
	unsigned char fwfixer_value;

144 145 146 147
	CK_MECHANISM_TYPE cipher;
	PK11SlotInfo *slot;
	PK11SymKey *symkey;
	SECItem *param;
148 149 150 151 152 153
};

/* For 2nd generation MS devices */
static const unsigned char crkey[] = {
	0x79, 0xac, 0x91, 0x79, 0x5c, 0xa1, 0x47, 0x8e,
	0x98, 0xe0, 0x0f, 0x3c, 0x59, 0x8f, 0x5f, 0x4b,
Daniel Drake's avatar
Daniel Drake committed
154 155
};

156 157 158
/***** REGISTER I/O *****/

typedef void (*write_regs_cb_fn)(struct fp_img_dev *dev, int status,
159 160
	void *user_data);

161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
struct write_regs_data {
	struct fp_img_dev *dev;
	write_regs_cb_fn callback;
	void *user_data;
};

static void write_regs_cb(struct libusb_transfer *transfer)
{
	struct write_regs_data *wrdata = transfer->user_data;
	struct libusb_control_setup *setup =
		libusb_control_transfer_get_setup(transfer);
	int r = 0;
	
	if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
		r = -EIO;
	else if (transfer->actual_length != setup->wLength)
		r = -EPROTO;

	g_free(transfer->buffer);
	libusb_free_transfer(transfer);
	wrdata->callback(wrdata->dev, r, wrdata->user_data);
	g_free(wrdata);
}

static int write_regs(struct fp_img_dev *dev, uint16_t first_reg,
	uint16_t num_regs, unsigned char *values, write_regs_cb_fn callback,
	void *user_data)
{
	struct write_regs_data *wrdata;
190
	struct libusb_transfer *transfer = fpi_usb_alloc();
191 192 193 194 195 196 197 198 199 200 201
	unsigned char *data;
	int r;

	wrdata = g_malloc(sizeof(*wrdata));
	wrdata->dev = dev;
	wrdata->callback = callback;
	wrdata->user_data = user_data;

	data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + num_regs);
	memcpy(data + LIBUSB_CONTROL_SETUP_SIZE, values, num_regs);
	libusb_fill_control_setup(data, CTRL_OUT, USB_RQ, first_reg, 0, num_regs);
202
	libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, write_regs_cb,
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
		wrdata, CTRL_TIMEOUT);

	r = libusb_submit_transfer(transfer);
	if (r < 0) {
		g_free(wrdata);
		g_free(data);
		libusb_free_transfer(transfer);
	}
	return r;
}

static int write_reg(struct fp_img_dev *dev, uint16_t reg,
	unsigned char value, write_regs_cb_fn callback, void *user_data)
{
	return write_regs(dev, reg, 1, &value, callback, user_data);
}

typedef void (*read_regs_cb_fn)(struct fp_img_dev *dev, int status,
221
	uint16_t num_regs, unsigned char *data, void *user_data);
222 223

struct read_regs_data {
224
	struct fp_img_dev *dev;
225
	read_regs_cb_fn callback;
226 227 228
	void *user_data;
};

229
static void read_regs_cb(struct libusb_transfer *transfer)
230
{
231 232 233 234
	struct read_regs_data *rrdata = transfer->user_data;
	struct libusb_control_setup *setup =
		libusb_control_transfer_get_setup(transfer);
	unsigned char *data = NULL;
235 236
	int r = 0;
	
237
	if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
238
		r = -EIO;
239
	else if (transfer->actual_length != setup->wLength)
240
		r = -EPROTO;
241 242
	else
		data = libusb_control_transfer_get_data(transfer);
243

244
	rrdata->callback(rrdata->dev, r, transfer->actual_length, data, rrdata->user_data);
245
	g_free(rrdata);
246 247
	g_free(transfer->buffer);
	libusb_free_transfer(transfer);
248 249
}

250 251
static int read_regs(struct fp_img_dev *dev, uint16_t first_reg,
	uint16_t num_regs, read_regs_cb_fn callback, void *user_data)
252
{
253
	struct read_regs_data *rrdata;
254
	struct libusb_transfer *transfer = fpi_usb_alloc();
255 256 257
	unsigned char *data;
	int r;

258 259 260 261
	rrdata = g_malloc(sizeof(*rrdata));
	rrdata->dev = dev;
	rrdata->callback = callback;
	rrdata->user_data = user_data;
262

263 264
	data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + num_regs);
	libusb_fill_control_setup(data, CTRL_IN, USB_RQ, first_reg, 0, num_regs);
265
	libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, read_regs_cb,
266
		rrdata, CTRL_TIMEOUT);
267 268 269

	r = libusb_submit_transfer(transfer);
	if (r < 0) {
270
		g_free(rrdata);
271 272
		g_free(data);
		libusb_free_transfer(transfer);
273
	}
274
	return r;
275 276
}

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
/*
 * HWSTAT
 *
 * This register has caused me a lot of headaches. It pretty much defines
 * code flow, and if you don't get it right, the pretty lights don't come on.
 * I think the situation is somewhat complicated by the fact that writing it
 * doesn't affect the read results in the way you'd expect -- but then again
 * it does have some obvious effects. Here's what we know
 *
 * BIT 7: LOW POWER MODE
 * When this bit is set, the device is partially turned off or something. Some
 * things, like firmware upload, need to be done in this state. But generally
 * we want to clear this bit during late initialization, which can sometimes
 * be tricky.
 *
 * BIT 2: SOMETHING WENT WRONG
 * Not sure about this, but see the init function, as when we detect it,
 * we reboot the device. Well, we mess with hwstat until this evil bit gets
 * cleared.
 *
 * BIT 1: IRQ PENDING
 * Just had a brainwave. This bit is set when the device is trying to deliver
299
 * an interrupt to the host. Maybe?
300 301
 */

302
static void response_cb(struct fp_img_dev *dev, int status, void *user_data)
Daniel Drake's avatar
Daniel Drake committed
303
{
Bastien Nocera's avatar
Bastien Nocera committed
304
	fpi_ssm *ssm = user_data;
305 306 307
	if (status == 0)
		fpi_ssm_next_state(ssm);
	else
308
		fpi_ssm_mark_failed(ssm, status);
Daniel Drake's avatar
Daniel Drake committed
309 310
}

311
static void challenge_cb(struct fp_img_dev *dev, int status,
312
	uint16_t num_regs, unsigned char *data, void *user_data)
Daniel Drake's avatar
Daniel Drake committed
313
{
Bastien Nocera's avatar
Bastien Nocera committed
314
	fpi_ssm *ssm = user_data;
315
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
316
	unsigned char *respdata;
317 318
	PK11Context *ctx;
	int r, outlen;
319

320
	r = status;
321
	if (status != 0) {
322
		fpi_ssm_mark_failed(ssm, status);
323
		return;
Daniel Drake's avatar
Daniel Drake committed
324 325
	}

326
	/* submit response */
327
	/* produce response from challenge */
328
	respdata = g_malloc(CR_LENGTH);
329 330 331 332 333 334 335 336 337 338 339 340 341 342
	ctx = PK11_CreateContextBySymKey(urudev->cipher, CKA_ENCRYPT,
					 urudev->symkey, urudev->param);
	if (PK11_CipherOp(ctx, respdata, &outlen, CR_LENGTH, data, CR_LENGTH) != SECSuccess
	    || PK11_Finalize(ctx) != SECSuccess) {
		fp_err("Failed to encrypt challenge data");
		r = -ECONNABORTED;
		g_free(respdata);
	}
	PK11_DestroyContext(ctx, PR_TRUE);

	if (r >= 0) {
		r = write_regs(dev, REG_RESPONSE, CR_LENGTH, respdata, response_cb, ssm);
		g_free(respdata);
	}
343
	if (r < 0)
344
		fpi_ssm_mark_failed(ssm, r);
Daniel Drake's avatar
Daniel Drake committed
345 346
}

347 348 349 350 351
/*
 * 2nd generation MS devices added an AES-based challenge/response
 * authentication scheme, where the device challenges the authenticity of the
 * driver.
 */
352 353 354
static void
sm_do_challenge_response(fpi_ssm           *ssm,
			 struct fp_img_dev *dev)
355
{
356
	int r;
357

358
	G_DEBUG_HERE();
359 360
	r = read_regs(dev, REG_CHALLENGE, CR_LENGTH, challenge_cb, ssm);
	if (r < 0)
361
		fpi_ssm_mark_failed(ssm, r);
362 363
}

364
/***** INTERRUPT HANDLING *****/
365

366
#define IRQ_HANDLER_IS_RUNNING(urudev) ((urudev)->irq_transfer)
367

368
static int start_irq_handler(struct fp_img_dev *dev);
369

370 371 372 373
static void irq_handler(struct libusb_transfer *transfer,
			struct fp_dev          *_dev,
			fpi_ssm                *ssm,
			void                   *user_data)
374
{
375 376
	struct fp_img_dev *dev = FP_IMG_DEV(_dev);
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
377
	unsigned char *data = transfer->buffer;
378 379
	uint16_t type;
	int r = 0;
380

381
	if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
382 383 384 385 386
		fp_dbg("cancelled");
		if (urudev->irqs_stopped_cb)
			urudev->irqs_stopped_cb(dev);
		urudev->irqs_stopped_cb = NULL;
		goto out;
387
	} else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
388 389
		r = -EIO;
		goto err;
390 391
	} else if (transfer->actual_length != transfer->length) {
		fp_err("short interrupt read? %d", transfer->actual_length);
392 393
		r = -EPROTO;
		goto err;
394 395
	}

396 397
	type = GUINT16_FROM_BE(*((uint16_t *) data));
	fp_dbg("recv irq type %04x", type);
398

399 400 401 402 403 404 405 406 407
	/* The 0800 interrupt seems to indicate imminent failure (0 bytes transfer)
	 * of the next scan. It still appears on occasion. */
	if (type == IRQDATA_DEATH)
		fp_warn("oh no! got the interrupt OF DEATH! expect things to go bad");

	if (urudev->irq_cb)
		urudev->irq_cb(dev, 0, type, urudev->irq_cb_data);
	else
		fp_dbg("ignoring interrupt");
408

409 410 411 412 413 414 415 416 417
	r = start_irq_handler(dev);
	if (r == 0)
		return;

err:
	if (urudev->irq_cb)
		urudev->irq_cb(dev, r, 0, urudev->irq_cb_data);
out:
	urudev->irq_transfer = NULL;
418 419
}

420
static int start_irq_handler(struct fp_img_dev *dev)
Daniel Drake's avatar
Daniel Drake committed
421
{
422
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
423
	fpi_usb_transfer *transfer;
424 425 426 427
	unsigned char *data;
	int r;

	data = g_malloc(IRQ_LENGTH);
428 429 430 431 432 433 434 435
	transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
					      NULL,
					      EP_INTR,
					      data,
					      IRQ_LENGTH,
					      irq_handler,
					      NULL,
					      0);
436 437

	urudev->irq_transfer = transfer;
438 439
	r = fpi_usb_submit_transfer(transfer);
	if (r < 0)
440 441
		urudev->irq_transfer = NULL;
	return r;
442
}
Daniel Drake's avatar
Daniel Drake committed
443

444 445
static void stop_irq_handler(struct fp_img_dev *dev, irqs_stopped_cb_fn cb)
{
446
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
447
	fpi_usb_transfer *transfer = urudev->irq_transfer;
448
	if (transfer) {
449
		fpi_usb_cancel_transfer(transfer);
450 451 452
		urudev->irqs_stopped_cb = cb;
	}
}
Daniel Drake's avatar
Daniel Drake committed
453

454
/***** STATE CHANGING *****/
455

456 457
static int execute_state_change(struct fp_img_dev *dev);

458 459
static void finger_presence_irq_cb(struct fp_img_dev *dev, int status,
	uint16_t type, void *user_data)
Daniel Drake's avatar
Daniel Drake committed
460
{
461 462 463 464 465 466 467 468 469
	if (status)
		fpi_imgdev_session_error(dev, status);
	else if (type == IRQDATA_FINGER_ON)
		fpi_imgdev_report_finger_status(dev, TRUE);
	else if (type == IRQDATA_FINGER_OFF)
		fpi_imgdev_report_finger_status(dev, FALSE);
	else
		fp_warn("ignoring unexpected interrupt %04x", type);
}
Daniel Drake's avatar
Daniel Drake committed
470

471
static void change_state_write_reg_cb(struct fp_img_dev *dev, int status,
472 473 474 475 476
	void *user_data)
{
	if (status)
		fpi_imgdev_session_error(dev, status);
}
Daniel Drake's avatar
Daniel Drake committed
477

478 479
static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state)
{
480
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
481

482
	switch (state) {
483
	case IMGDEV_STATE_INACTIVE:
484 485
	case IMGDEV_STATE_AWAIT_FINGER_ON:
	case IMGDEV_STATE_AWAIT_FINGER_OFF:
486 487
	case IMGDEV_STATE_CAPTURE:
		break;
488 489 490
	default:
		fp_err("unrecognised state %d", state);
		return -EINVAL;
491
	}
492 493 494 495 496 497

	urudev->activate_state = state;
	if (urudev->img_transfer != NULL)
		return 0;

	return execute_state_change(dev);
Daniel Drake's avatar
Daniel Drake committed
498 499
}

500
/***** GENERIC STATE MACHINE HELPER FUNCTIONS *****/
Daniel Drake's avatar
Daniel Drake committed
501

502
static void sm_write_reg_cb(struct fp_img_dev *dev, int result, void *user_data)
503
{
Bastien Nocera's avatar
Bastien Nocera committed
504
	fpi_ssm *ssm = user_data;
Daniel Drake's avatar
Daniel Drake committed
505

506
	if (result)
507
		fpi_ssm_mark_failed(ssm, result);
508
	else
509
		fpi_ssm_next_state(ssm);
Daniel Drake's avatar
Daniel Drake committed
510 511
}

512 513 514 515 516 517
static void
sm_write_regs(fpi_ssm           *ssm,
	      struct fp_img_dev *dev,
	      uint16_t           first_reg,
	      uint16_t           num_regs,
	      void              *data)
Daniel Drake's avatar
Daniel Drake committed
518
{
519
	int r = write_regs(dev, first_reg, num_regs, data, sm_write_reg_cb, ssm);
Daniel Drake's avatar
Daniel Drake committed
520
	if (r < 0)
521
		fpi_ssm_mark_failed(ssm, r);
Daniel Drake's avatar
Daniel Drake committed
522 523
}

524 525 526 527 528
static void
sm_write_reg(fpi_ssm           *ssm,
	     struct fp_img_dev *dev,
	     uint16_t           reg,
	     unsigned char      value)
529
{
530
	sm_write_regs(ssm, dev, reg, 1, &value);
531 532
}

533
static void sm_read_reg_cb(struct fp_img_dev *dev, int result,
534
	uint16_t num_regs, unsigned char *data, void *user_data)
535
{
Bastien Nocera's avatar
Bastien Nocera committed
536
	fpi_ssm *ssm = user_data;
537
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
Daniel Drake's avatar
Daniel Drake committed
538

539
	if (result) {
540
		fpi_ssm_mark_failed(ssm, result);
541
	} else {
542 543
		memcpy(urudev->last_reg_rd, data, num_regs);
		fp_dbg("reg value %x", urudev->last_reg_rd[0]);
544 545 546
		fpi_ssm_next_state(ssm);
	}
}
Daniel Drake's avatar
Daniel Drake committed
547

548 549 550 551 552
static void
sm_read_regs(fpi_ssm           *ssm,
	     struct fp_img_dev *dev,
	     uint16_t           reg,
	     uint16_t           num_regs)
553
{
554
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
555
	int r;
556 557

	if (num_regs > sizeof(urudev->last_reg_rd)) {
558
		fpi_ssm_mark_failed(ssm, -EIO);
559 560 561 562 563
		return;
	}

	fp_dbg("read %d regs at %x", num_regs, reg);
	r = read_regs(dev, reg, num_regs, sm_read_reg_cb, ssm);
564
	if (r < 0)
565
		fpi_ssm_mark_failed(ssm, r);
566
}
567

568 569 570 571
static void
sm_read_reg(fpi_ssm           *ssm,
	    struct fp_img_dev *dev,
	    uint16_t           reg)
572
{
573
	sm_read_regs(ssm, dev, reg, 1);
574
}
575

576 577 578 579
static void
sm_set_hwstat(fpi_ssm           *ssm,
	      struct fp_img_dev *dev,
	      unsigned char      value)
580 581
{
	fp_dbg("set %02x", value);
582
	sm_write_reg(ssm, dev, REG_HWSTAT, value);
583 584
}

585
/***** IMAGING LOOP *****/
586

587 588 589 590 591 592 593
enum imaging_states {
	IMAGING_CAPTURE,
	IMAGING_SEND_INDEX,
	IMAGING_READ_KEY,
	IMAGING_DECODE,
	IMAGING_REPORT_IMAGE,
	IMAGING_NUM_STATES
594 595
};

596 597 598 599 600 601 602 603 604 605 606 607
struct uru4k_image {
	uint8_t		unknown_00[4];
	uint16_t	num_lines;
	uint8_t		key_number;
	uint8_t		unknown_07[9];
	struct {
		uint8_t	flags;
		uint8_t	num_lines;
	} block_info[15];
	uint8_t		unknown_2E[18];
	uint8_t		data[IMAGE_HEIGHT][IMAGE_WIDTH];
};
Daniel Drake's avatar
Daniel Drake committed
608

609 610 611 612 613
static void image_transfer_cb(struct libusb_transfer *transfer,
			      struct fp_dev          *dev,
			      fpi_ssm                *ssm,
			      void                   *user_data)
{
614 615
	if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
		fp_dbg("cancelled");
616
		fpi_ssm_mark_failed(ssm, -ECANCELED);
617 618
	} else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
		fp_dbg("error");
619
		fpi_ssm_mark_failed(ssm, -EIO);
620
	} else {
621 622 623 624
		struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev);

		urudev->img_data = g_memdup(transfer->buffer, sizeof(struct uru4k_image));
		urudev->img_data_actual_length = transfer->actual_length;
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
		fpi_ssm_next_state(ssm);
	}
}

enum {
	BLOCKF_CHANGE_KEY	= 0x80,
	BLOCKF_NO_KEY_UPDATE	= 0x04,
	BLOCKF_ENCRYPTED		= 0x02,
	BLOCKF_NOT_PRESENT	= 0x01,
};

static uint32_t update_key(uint32_t key)
{
	/* linear feedback shift register
	 * taps at bit positions 1 3 4 7 11 13 20 23 26 29 32 */
	uint32_t bit = key & 0x9248144d;
	bit ^= bit << 16;
	bit ^= bit << 8;
	bit ^= bit << 4;
	bit ^= bit << 2;
	bit ^= bit << 1;
	return (bit & 0x80000000) | (key >> 1);
}

static uint32_t do_decode(uint8_t *data, int num_bytes, uint32_t key)
{
	uint8_t xorbyte;
	int i;

	for (i = 0; i < num_bytes - 1; i++) {
		/* calculate xor byte and update key */
		xorbyte  = ((key >>  4) & 1) << 0;
		xorbyte |= ((key >>  8) & 1) << 1;
		xorbyte |= ((key >> 11) & 1) << 2;
		xorbyte |= ((key >> 14) & 1) << 3;
		xorbyte |= ((key >> 18) & 1) << 4;
		xorbyte |= ((key >> 21) & 1) << 5;
		xorbyte |= ((key >> 24) & 1) << 6;
		xorbyte |= ((key >> 29) & 1) << 7;
		key = update_key(key);

		/* decrypt data */
		data[i] = data[i+1] ^ xorbyte;
668
	}
669 670 671 672

	/* the final byte is implictly zero */
	data[i] = 0;
	return update_key(key);
Daniel Drake's avatar
Daniel Drake committed
673 674
}

675 676 677 678 679
static int calc_dev2(struct uru4k_image *img)
{
	uint8_t *b[2] = { NULL, NULL };
	int res = 0, mean = 0, i, r, j, idx;

680
	for (i = r = idx = 0; i < G_N_ELEMENTS(img->block_info) && idx < 2; i++) {
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
		if (img->block_info[i].flags & BLOCKF_NOT_PRESENT)
			continue;
		for (j = 0; j < img->block_info[i].num_lines && idx < 2; j++)
			b[idx++] = img->data[r++];
	}
	if (!b[0] || !b[1]) {
		fp_dbg("NULL! %p %p", b[0], b[1]);
		return 0;
	}
	for (i = 0; i < IMAGE_WIDTH; i++)
		mean += (int)b[0][i] + (int)b[1][i];

	mean /= IMAGE_WIDTH;

	for (i = 0; i < IMAGE_WIDTH; i++) {
		int dev = (int)b[0][i] + (int)b[1][i] - mean;
		res += dev * dev;
	}

	return res / IMAGE_WIDTH;
}

703
static void imaging_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
704
{
705
	struct fp_img_dev *dev = user_data;
706
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
707 708 709 710
	struct uru4k_image *img = urudev->img_data;
	struct fp_img *fpimg;
	uint32_t key;
	uint8_t flags, num_lines;
711
	int i, r, to, dev2;
712
	char buf[5];
713

714
	switch (fpi_ssm_get_cur_state(ssm)) {
715 716 717
	case IMAGING_CAPTURE:
		urudev->img_lines_done = 0;
		urudev->img_block = 0;
718 719 720
		r = fpi_usb_submit_transfer(urudev->img_transfer);
		if (r < 0) {
			urudev->img_transfer = NULL;
721
			fpi_ssm_mark_failed(ssm, -EIO);
722
		}
723
		break;
724 725 726 727
	case IMAGING_SEND_INDEX:
		fp_dbg("hw header lines %d", img->num_lines);

		if (img->num_lines >= IMAGE_HEIGHT ||
728
		    urudev->img_data_actual_length < img->num_lines * IMAGE_WIDTH + 64) {
729
			fp_err("bad captured image (%d lines) or size mismatch %d < %d",
730
				img->num_lines,
731
				urudev->img_data_actual_length,
732 733
				img->num_lines * IMAGE_WIDTH + 64);
			fpi_ssm_jump_to_state(ssm, IMAGING_CAPTURE);
734 735
			return;
		}
736
		if (!urudev->profile->encryption) {
737 738 739 740 741 742 743
			dev2 = calc_dev2(img);
			fp_dbg("dev2: %d", dev2);
			if (dev2 < ENC_THRESHOLD) {
				fpi_ssm_jump_to_state(ssm, IMAGING_REPORT_IMAGE);
				return;
			}
			fp_info("image seems to be encrypted");
744 745 746 747 748 749
		}
		buf[0] = img->key_number;
		buf[1] = urudev->img_enc_seed;
		buf[2] = urudev->img_enc_seed >> 8;
		buf[3] = urudev->img_enc_seed >> 16;
		buf[4] = urudev->img_enc_seed >> 24;
750
		sm_write_regs(ssm, dev, REG_SCRAMBLE_DATA_INDEX, 5, buf);
751
		break;
752
	case IMAGING_READ_KEY:
753
		sm_read_regs(ssm, dev, REG_SCRAMBLE_DATA_KEY, 4);
754 755 756 757 758 759 760 761 762
		break;
	case IMAGING_DECODE:
		key  = urudev->last_reg_rd[0];
		key |= urudev->last_reg_rd[1] << 8;
		key |= urudev->last_reg_rd[2] << 16;
		key |= urudev->last_reg_rd[3] << 24;
		key ^= urudev->img_enc_seed;

		fp_dbg("encryption id %02x -> key %08x", img->key_number, key);
763
		while (urudev->img_block < G_N_ELEMENTS(img->block_info) &&
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
				urudev->img_lines_done < img->num_lines) {
			flags = img->block_info[urudev->img_block].flags;
			num_lines = img->block_info[urudev->img_block].num_lines;
			if (num_lines == 0)
				break;

			fp_dbg("%d %02x %d", urudev->img_block, flags, num_lines);
			if (flags & BLOCKF_CHANGE_KEY) {
				fp_dbg("changing encryption keys.\n");
				img->block_info[urudev->img_block].flags &= ~BLOCKF_CHANGE_KEY;
				img->key_number++;
				urudev->img_enc_seed = rand();
				fpi_ssm_jump_to_state(ssm, IMAGING_SEND_INDEX);
				return;
			}
			switch (flags & (BLOCKF_NO_KEY_UPDATE | BLOCKF_ENCRYPTED)) {
			case BLOCKF_ENCRYPTED:
				fp_dbg("decoding %d lines", num_lines);
				key = do_decode(&img->data[urudev->img_lines_done][0],
						IMAGE_WIDTH*num_lines, key);
				break;
			case 0:
				fp_dbg("skipping %d lines", num_lines);
				for (r = 0; r < IMAGE_WIDTH*num_lines; r++)
					key = update_key(key);
				break;
			}
			if ((flags & BLOCKF_NOT_PRESENT) == 0)
				urudev->img_lines_done += num_lines;
			urudev->img_block++;
		}
		fpi_ssm_next_state(ssm);
		break;
	case IMAGING_REPORT_IMAGE:
		fpimg = fpi_img_new_for_imgdev(dev);

		to = r = 0;
801
		for (i = 0; i < G_N_ELEMENTS(img->block_info) && r < img->num_lines; i++) {
802 803 804 805 806 807 808 809 810
			flags = img->block_info[i].flags;
			num_lines = img->block_info[i].num_lines;
			if (num_lines == 0)
				break;
			memcpy(&fpimg->data[to], &img->data[r][0],
				num_lines * IMAGE_WIDTH);
			if (!(flags & BLOCKF_NOT_PRESENT))
				r += num_lines;
			to += num_lines * IMAGE_WIDTH;
811
		}
812 813 814 815 816 817 818 819 820 821

		fpimg->flags = FP_IMG_COLORS_INVERTED;
		if (!urudev->profile->encryption)
			fpimg->flags |= FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
		fpi_imgdev_image_captured(dev, fpimg);

		if (urudev->activate_state == IMGDEV_STATE_CAPTURE)
			fpi_ssm_jump_to_state(ssm, IMAGING_CAPTURE);
		else
			fpi_ssm_mark_completed(ssm);
822 823 824
		break;
	}
}
825

826
static void imaging_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
827
{
828
	struct fp_img_dev *dev = user_data;
829
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
830
	int r = fpi_ssm_get_error(ssm);
831 832
	fpi_ssm_free(ssm);

833 834 835 836 837 838
	/* Report error before exiting imaging loop - the error handler
	 * can request state change, which needs to be postponed to end of
	 * this function. */
	if (r)
		fpi_imgdev_session_error(dev, r);

839 840 841
	/* Freed by callback or cancellation */
	urudev->img_transfer = NULL;

842 843
	g_free(urudev->img_data);
	urudev->img_data = NULL;
844
	urudev->img_data_actual_length = 0;
845 846 847 848 849 850 851 852

	r = execute_state_change(dev);
	if (r)
		fpi_imgdev_session_error(dev, r);
}

/***** INITIALIZATION *****/

853 854 855 856
/* After closing an app and setting hwstat to 0x80, my ms keyboard gets in a
 * confused state and returns hwstat 0x85. On next app run, we don't get the
 * 56aa interrupt. This is the best way I've found to fix it: mess around
 * with hwstat until it starts returning more recognisable values. This
857
 * doesn't happen on my other devices: uru4000, uru4000b, ms fp rdr v2
858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
 *
 * The windows driver copes with this OK, but then again it uploads firmware
 * right after reading the 0x85 hwstat, allowing some time to pass before it
 * attempts to tweak hwstat again...
 *
 * This is implemented with a reboot power state machine. the ssm runs during
 * initialization if bits 2 and 7 are set in hwstat. it masks off the 4 high
 * hwstat bits then checks that bit 1 is set. if not, it pauses before reading
 * hwstat again. machine completes when reading hwstat shows bit 1 is set,
 * and fails after 100 tries. */

enum rebootpwr_states {
	REBOOTPWR_SET_HWSTAT = 0,
	REBOOTPWR_GET_HWSTAT,
	REBOOTPWR_CHECK_HWSTAT,
	REBOOTPWR_PAUSE,
	REBOOTPWR_NUM_STATES,
};
876

877 878 879
static void
rebootpwr_pause_cb(struct fp_dev *dev,
		   void          *data)
880
{
Bastien Nocera's avatar
Bastien Nocera committed
881
	fpi_ssm *ssm = data;
882
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev);
883

884 885
	if (!--urudev->rebootpwr_ctr) {
		fp_err("could not reboot device power");
886
		fpi_ssm_mark_failed(ssm, -EIO);
887 888 889
	} else {
		fpi_ssm_jump_to_state(ssm, REBOOTPWR_GET_HWSTAT);
	}
890 891
}

892
static void rebootpwr_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
Daniel Drake's avatar
Daniel Drake committed
893
{
894
	struct fp_img_dev *dev = user_data;
895
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
Daniel Drake's avatar
Daniel Drake committed
896

897
	switch (fpi_ssm_get_cur_state(ssm)) {
898 899
	case REBOOTPWR_SET_HWSTAT:
		urudev->rebootpwr_ctr = 100;
900
		sm_set_hwstat(ssm, dev, urudev->last_hwstat & 0xf);
901 902
		break;
	case REBOOTPWR_GET_HWSTAT:
903
		sm_read_reg(ssm, dev, REG_HWSTAT);
904 905
		break;
	case REBOOTPWR_CHECK_HWSTAT:
906
		urudev->last_hwstat = urudev->last_reg_rd[0];
907
		if (urudev->last_hwstat & 0x1)
908 909 910 911 912
			fpi_ssm_mark_completed(ssm);
		else
			fpi_ssm_next_state(ssm);
		break;
	case REBOOTPWR_PAUSE:
913
		if (fpi_timeout_add(10, rebootpwr_pause_cb, _dev, ssm) == NULL)
914
			fpi_ssm_mark_failed(ssm, -ETIME);
915
		break;
Daniel Drake's avatar
Daniel Drake committed
916
	}
917 918
}

919
/* After messing with the device firmware in its low-power state, we have to
920 921
 * power it back up and wait for interrupt notification. It's not quite as easy
 * as that: the combination of both modifying firmware *and* doing C-R auth on
922
 * my ms fp v2 device causes us not to get the 56aa interrupt and
923 924 925 926 927 928 929 930 931 932 933 934 935 936
 * for the hwstat write not to take effect. We have to loop a few times,
 * authenticating each time, until the device wakes up.
 *
 * This is implemented as the powerup state machine below. Pseudo-code:

	status = get_hwstat();
	for (i = 0; i < 100; i++) {
		set_hwstat(status & 0xf);
		if ((get_hwstat() & 0x80) == 0)
			break;

		usleep(10000);
		if (need_auth_cr)
			auth_cr();
Daniel Drake's avatar
Daniel Drake committed
937 938
	}

939 940
	if (tmp & 0x80)
		error("could not power up device");
941

942
 */
Daniel Drake's avatar
Daniel Drake committed
943

944 945 946 947 948 949 950
enum powerup_states {
	POWERUP_INIT = 0,
	POWERUP_SET_HWSTAT,
	POWERUP_GET_HWSTAT,
	POWERUP_CHECK_HWSTAT,
	POWERUP_PAUSE,
	POWERUP_CHALLENGE_RESPONSE,
951
	POWERUP_CHALLENGE_RESPONSE_SUCCESS,
952 953 954
	POWERUP_NUM_STATES,
};

955 956 957
static void
powerup_pause_cb(struct fp_dev *dev,
		 void          *data)
958
{
Bastien Nocera's avatar
Bastien Nocera committed
959
	fpi_ssm *ssm = data;
960
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev);
Daniel Drake's avatar
Daniel Drake committed
961

962 963
	if (!--urudev->powerup_ctr) {
		fp_err("could not power device up");
964
		fpi_ssm_mark_failed(ssm, -EIO);
965 966 967 968 969 970 971
	} else if (!urudev->profile->auth_cr) {
		fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT);
	} else {
		fpi_ssm_next_state(ssm);
	}
}

972
static void powerup_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
973
{
974
	struct fp_img_dev *dev = user_data;
975
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
976

977
	switch (fpi_ssm_get_cur_state(ssm)) {
978 979
	case POWERUP_INIT:
		urudev->powerup_ctr = 100;
980
		urudev->powerup_hwstat = urudev->last_hwstat & 0xf;
981 982 983
		fpi_ssm_next_state(ssm);
		break;
	case POWERUP_SET_HWSTAT:
984
		sm_set_hwstat(ssm, dev, urudev->powerup_hwstat);
985 986
		break;
	case POWERUP_GET_HWSTAT:
987
		sm_read_reg(ssm, dev, REG_HWSTAT);
988 989
		break;
	case POWERUP_CHECK_HWSTAT:
990 991
		urudev->last_hwstat = urudev->last_reg_rd[0];
		if ((urudev->last_reg_rd[0] & 0x80) == 0)
992 993 994 995 996
			fpi_ssm_mark_completed(ssm);
		else
			fpi_ssm_next_state(ssm);
		break;
	case POWERUP_PAUSE:
997
		if (fpi_timeout_add(10, powerup_pause_cb, _dev, ssm) == NULL)
998
			fpi_ssm_mark_failed(ssm, -ETIME);
999 1000
		break;
	case POWERUP_CHALLENGE_RESPONSE:
1001
		sm_do_challenge_response(ssm, dev);
1002 1003
		break;
	case POWERUP_CHALLENGE_RESPONSE_SUCCESS:
1004
		fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT);
1005 1006 1007
		break;
	}
}
Daniel Drake's avatar
Daniel Drake committed
1008

1009 1010
/*
 * This is the main initialization state machine. As pseudo-code:
Daniel Drake's avatar
Daniel Drake committed
1011

1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
	status = get_hwstat();

	// correct device power state
	if ((status & 0x84) == 0x84)
		run_reboot_sm();

	// power device down
	if ((status & 0x80) == 0)
		set_hwstat(status | 0x80);

	// power device up
	run_powerup_sm();
	await_irq(IRQDATA_SCANPWR_ON);
 */

enum init_states {
	INIT_GET_HWSTAT = 0,
	INIT_CHECK_HWSTAT_REBOOT,
	INIT_REBOOT_POWER,
	INIT_CHECK_HWSTAT_POWERDOWN,
	INIT_POWERUP,
	INIT_AWAIT_SCAN_POWER,
	INIT_DONE,
1035 1036
	INIT_GET_VERSION,
	INIT_REPORT_VERSION,
1037 1038 1039 1040 1041 1042
	INIT_NUM_STATES,
};

static void init_scanpwr_irq_cb(struct fp_img_dev *dev, int status,
	uint16_t type, void *user_data)
{
Bastien Nocera's avatar
Bastien Nocera committed
1043
	fpi_ssm *ssm = user_data;
1044
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
1045 1046

	if (status)
1047
		fpi_ssm_mark_failed(ssm, status);
1048 1049
	else if (type != IRQDATA_SCANPWR_ON)
		fp_dbg("ignoring interrupt");
1050
	else if (fpi_ssm_get_cur_state(ssm) != INIT_AWAIT_SCAN_POWER) {
1051 1052 1053 1054
		fp_dbg("early scanpwr interrupt");
		urudev->scanpwr_irq_timeouts = -1;
	} else {
		fp_dbg("late scanpwr interrupt");
1055
		fpi_ssm_next_state(ssm);
1056
	}
1057 1058
}

1059 1060 1061
static void
init_scanpwr_timeout(struct fp_dev *dev,
		     void          *user_data)
1062
{
Bastien Nocera's avatar
Bastien Nocera committed
1063
	fpi_ssm *ssm = user_data;
1064
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev);
1065 1066 1067 1068 1069 1070 1071

	fp_warn("powerup timed out");
	urudev->irq_cb = NULL;
	urudev->scanpwr_irq_timeout = NULL;

	if (++urudev->scanpwr_irq_timeouts >= 3) {
		fp_err("powerup timed out 3 times, giving up");
1072
		fpi_ssm_mark_failed(ssm, -ETIMEDOUT);
1073 1074 1075 1076 1077
	} else {
		fpi_ssm_jump_to_state(ssm, INIT_GET_HWSTAT);
	}
}

1078
static void init_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
1079
{
1080
	struct fp_img_dev *dev = user_data;
1081
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
Daniel Drake's avatar
Daniel Drake committed
1082

1083
	switch (fpi_ssm_get_cur_state(ssm)) {
1084
	case INIT_GET_HWSTAT:
1085
		sm_read_reg(ssm, dev, REG_HWSTAT);
1086 1087
		break;
	case INIT_CHECK_HWSTAT_REBOOT:
1088
		urudev->last_hwstat = urudev->last_reg_rd[0];
1089
		if ((urudev->last_hwstat & 0x84) == 0x84)
1090 1091 1092 1093 1094
			fpi_ssm_next_state(ssm);
		else
			fpi_ssm_jump_to_state(ssm, INIT_CHECK_HWSTAT_POWERDOWN);
		break;
	case INIT_REBOOT_POWER: ;
1095
		fpi_ssm *rebootsm = fpi_ssm_new(FP_DEV(dev), rebootpwr_run_state,
1096
			REBOOTPWR_NUM_STATES, dev);
1097 1098 1099
		fpi_ssm_start_subsm(ssm, rebootsm);
		break;
	case INIT_CHECK_HWSTAT_POWERDOWN:
1100
		if ((urudev->last_hwstat & 0x80) == 0)
1101
			sm_set_hwstat(ssm, dev, urudev->last_hwstat | 0x80);
1102 1103 1104 1105
		else
			fpi_ssm_next_state(ssm);
		break;
	case INIT_POWERUP: ;
1106
		if (!IRQ_HANDLER_IS_RUNNING(urudev)) {
1107
			fpi_ssm_mark_failed(ssm, -EIO);
1108 1109 1110 1111 1112
			break;
		}
		urudev->irq_cb_data = ssm;
		urudev->irq_cb = init_scanpwr_irq_cb;

1113
		fpi_ssm *powerupsm = fpi_ssm_new(FP_DEV(dev), powerup_run_state,
1114
			POWERUP_NUM_STATES, dev);
1115 1116 1117
		fpi_ssm_start_subsm(ssm, powerupsm);
		break;
	case INIT_AWAIT_SCAN_POWER:
1118 1119
		if (urudev->scanpwr_irq_timeouts < 0) {
			fpi_ssm_next_state(ssm);
1120 1121 1122 1123 1124 1125 1126
			break;
		}

		/* sometimes the 56aa interrupt that we are waiting for never arrives,
		 * so we include this timeout loop to retry the whole process 3 times
		 * if we don't get an irq any time soon. */
		urudev->scanpwr_irq_timeout = fpi_timeout_add(300,
1127 1128
							      init_scanpwr_timeout,
							      _dev, ssm);
1129
		if (!urudev->scanpwr_irq_timeout) {
1130
			fpi_ssm_mark_failed(ssm, -ETIME);
1131
			break;
1132
		}
1133 1134
		break;
	case INIT_DONE:
1135 1136 1137 1138
		if (urudev->scanpwr_irq_timeout) {
			fpi_timeout_cancel(urudev->scanpwr_irq_timeout);
			urudev->scanpwr_irq_timeout = NULL;
		}
1139 1140
		urudev->irq_cb_data = NULL;
		urudev->irq_cb = NULL;
1141 1142 1143
		fpi_ssm_next_state(ssm);
		break;
	case INIT_GET_VERSION:
1144
		sm_read_regs(ssm, dev, REG_DEVICE_INFO, 16);
1145 1146 1147 1148 1149 1150 1151
		break;
	case INIT_REPORT_VERSION:
		/* Likely hardware revision, and firmware version.
		 * Not sure which is which. */
		fp_info("Versions %02x%02x and %02x%02x",
			urudev->last_reg_rd[10], urudev->last_reg_rd[11],
			urudev->last_reg_rd[4],  urudev->last_reg_rd[5]);
1152 1153
		fpi_ssm_mark_completed(ssm);
		break;
Daniel Drake's avatar
Daniel Drake committed
1154
	}
1155
}
Daniel Drake's avatar
Daniel Drake committed
1156

1157
static void activate_initsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
1158
{
1159
	struct fp_img_dev *dev = user_data;
1160
	int r = fpi_ssm_get_error(ssm);
1161 1162 1163 1164 1165
	fpi_ssm_free(ssm);

	if (r) {
		fpi_imgdev_activate_complete(dev, r);
		return;
Daniel Drake's avatar
Daniel Drake committed
1166 1167
	}

1168
	r = execute_state_change(dev);
1169 1170 1171 1172 1173 1174 1175 1176 1177
	fpi_imgdev_activate_complete(dev, r);
}

/* FIXME: having state parameter here is kinda useless, will we ever
 * see a scenario where the parameter is useful so early on in the activation
 * process? asynchronity means that it'll only be used in a later function
 * call. */
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
{
1178
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
Bastien Nocera's avatar
Bastien Nocera committed
1179
	fpi_ssm *ssm;
1180 1181 1182 1183 1184 1185
	int r;

	r = start_irq_handler(dev);
	if (r < 0)
		return r;

1186
	urudev->scanpwr_irq_timeouts = 0;
1187
	urudev->activate_state = state;
1188
	ssm = fpi_ssm_new(FP_DEV(dev), init_run_state, INIT_NUM_STATES, dev);
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
	fpi_ssm_start(ssm, activate_initsm_complete);
	return 0;
}

/***** DEINITIALIZATION *****/

static void deactivate_irqs_stopped(struct fp_img_dev *dev)
{
	fpi_imgdev_deactivate_complete(dev);
}

1200 1201
static void deactivate_write_reg_cb(struct fp_img_dev *dev, int status,
	void *user_data)
1202 1203 1204 1205 1206
{
	stop_irq_handler(dev, deactivate_irqs_stopped);
}

static void dev_deactivate(struct fp_img_dev *dev)
1207 1208 1209 1210 1211
{
	dev_change_state(dev, IMGDEV_STATE_INACTIVE);
}

static int execute_state_change(struct fp_img_dev *dev)
1212
{
1213
	struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
Bastien Nocera's avatar
Bastien Nocera committed
1214
	fpi_ssm *ssm;
1215
	void *img_data;
1216

1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
	switch (urudev->activate_state) {
	case IMGDEV_STATE_INACTIVE:
		fp_dbg("deactivating");
		urudev->irq_cb = NULL;
		urudev->irq_cb_data = NULL;
		return write_reg(dev, REG_MODE, MODE_OFF,
			deactivate_write_reg_cb, NULL);
		break;

	case IMGDEV_STATE_AWAIT_FINGER_ON:
		fp_dbg("wait finger on");
		if (!IRQ_HANDLER_IS_RUNNING(urudev))
			return -EIO;
		urudev->irq_cb = finger_presence_irq_cb;
		return write_reg(dev, REG_MODE, MODE_AWAIT_FINGER_ON,
			change_state_write_reg_cb, NULL);

	case IMGDEV_STATE_CAPTURE:
		fp_dbg("starting capture");
		urudev->irq_cb = NULL;

1238 1239
		ssm = fpi_ssm_new(FP_DEV(dev), imaging_run_state, IMAGING_NUM_STATES, dev);
		img_data = g_malloc(sizeof(struct uru4k_image));
1240
		urudev->img_enc_seed = rand();
1241 1242 1243 1244 1245 1246 1247 1248
		urudev->img_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
								  ssm,
								  EP_DATA,
								  img_data,
								  sizeof(struct uru4k_image),
								  image_transfer_cb,
								  NULL,
								  0);
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264

		fpi_ssm_start(ssm, imaging_complete);

		return write_reg(dev, REG_MODE, MODE_CAPTURE,
			change_state_write_reg_cb, NULL);

	case IMGDEV_STATE_AWAIT_FINGER_OFF:
		fp_dbg("await finger off");
		if (!IRQ_HANDLER_IS_RUNNING(urudev))
			return -EIO;
		urudev->irq_cb = finger_presence_irq_cb;
		return write_reg(dev, REG_MODE, MODE_AWAIT_FINGER_OFF,
			change_state_write_reg_cb, NULL);
	}

	return 0;
1265 1266 1267 1268
}

/***** LIBRARY STUFF *****/

Daniel Drake's avatar
Daniel Drake committed
1269 1270
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
1271
	struct libusb_config_descriptor *config;
1272 1273 1274
	const struct libusb_interface *iface = NULL;
	const struct libusb_interface_descriptor *iface_desc;
	const struct libusb_endpoint_descriptor *ep;
Daniel Drake's avatar
Daniel Drake committed
1275
	struct uru4k_dev *urudev;
1276 1277
	SECStatus rv;
	SECItem item;
Daniel Drake's avatar
Daniel Drake committed
1278 1279 1280 1281
	int i;
	int r;

	/* Find fingerprint interface */
1282
	r = libusb_get_config_descriptor(libusb_get_device(fpi_dev_get_usb_dev(FP_DEV(dev))), 0, &config);
1283 1284 1285 1286
	if (r < 0) {
		fp_err("Failed to get config descriptor");
		return r;
	}
Daniel Drake's avatar
Daniel Drake committed
1287
	for (i = 0; i < config->bNumInterfaces; i++) {
1288
		const struct libusb_interface *cur_iface = &config->interface[i];
Daniel Drake's avatar
Daniel Drake committed
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303

		if (cur_iface->num_altsetting < 1)
			continue;

		iface_desc = &cur_iface->altsetting[0];
		if (iface_desc->bInterfaceClass == 255
				&& iface_desc->bInterfaceSubClass == 255 
				&& iface_desc->bInterfaceProtocol == 255) {
			iface = cur_iface;
			break;
		}
	}

	if (iface == NULL) {
		fp_err("could not find interface");
1304 1305
		r = -ENODEV;
		goto out;
Daniel Drake's avatar
Daniel Drake committed
1306 1307 1308 1309 1310 1311
	}

	/* Find/check endpoints */

	if (iface_desc->bNumEndpoints != 2) {
		fp_err("found %d endpoints!?", iface_desc->bNumEndpoints);
1312 1313
		r = -ENODEV;
		goto out;
Daniel Drake's avatar
Daniel Drake committed
1314 1315 1316 1317
	}

	ep = &iface_desc->endpoint[0];
	if (ep->bEndpointAddress != EP_INTR
1318 1319
			|| (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) !=
				LIBUSB_TRANSFER_TYPE_INTERRUPT) {
Daniel Drake's avatar
Daniel Drake committed
1320
		fp_err("unrecognised interrupt endpoint");
1321 1322
		r = -ENODEV;
		goto out;
Daniel Drake's avatar
Daniel Drake committed
1323 1324 1325 1326
	}

	ep = &iface_desc->endpoint[1];
	if (ep->bEndpointAddress != EP_DATA
1327 1328
			|| (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) !=
				LIBUSB_TRANSFER_TYPE_BULK) {
Daniel Drake's avatar
Daniel Drake committed
1329
		fp_err("unrecognised bulk endpoint");
1330 1331
		r = -ENODEV;
		goto out;