Commit d731d5f3 authored by Daniel Drake's avatar Daniel Drake

aeslib: port to asynchronous model

parent 3048b371
/* /*
* Shared functions between libfprint Authentec drivers * Shared functions between libfprint Authentec drivers
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
...@@ -33,71 +33,127 @@ ...@@ -33,71 +33,127 @@
#define EP_IN (1 | LIBUSB_ENDPOINT_IN) #define EP_IN (1 | LIBUSB_ENDPOINT_IN)
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT) #define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
static int do_write_regv(struct fp_img_dev *dev, struct write_regv_data {
const struct aes_regwrite *regs, unsigned int num) struct fp_img_dev *imgdev;
unsigned int num_regs;
const struct aes_regwrite *regs;
unsigned int offset;
aes_write_regv_cb callback;
};
static void continue_write_regv(struct write_regv_data *wdata);
/* libusb bulk callback for regv write completion transfer. continues the
* transaction */
static void write_regv_trf_complete(libusb_dev_handle *devh,
libusb_urb_handle *urbh, enum libusb_urb_cb_status status,
unsigned char endpoint, int rqlength, unsigned char *data,
int actual_length, void *user_data)
{ {
struct write_regv_data *wdata = user_data;
g_free(data);
libusb_urb_handle_free(urbh);
if (status != FP_URB_COMPLETED)
wdata->callback(wdata->imgdev, -EIO);
else if (rqlength != actual_length)
wdata->callback(wdata->imgdev, -EPROTO);
else
continue_write_regv(wdata);
}
/* write from wdata->offset to upper_bound (inclusive) of wdata->regs */
static int do_write_regv(struct write_regv_data *wdata, int upper_bound)
{
unsigned int offset = wdata->offset;
unsigned int num = upper_bound - offset + 1;
size_t alloc_size = num * 2; size_t alloc_size = num * 2;
unsigned char *data = g_malloc(alloc_size); unsigned char *data = g_malloc(alloc_size);
unsigned int i; unsigned int i;
size_t offset = 0; size_t data_offset = 0;
int r; struct libusb_urb_handle *urbh;
int transferred;
struct libusb_bulk_transfer msg = { struct libusb_bulk_transfer msg = {
.endpoint = EP_OUT, .endpoint = EP_OUT,
.data = data, .data = data,
.length = alloc_size, .length = alloc_size,
}; };
fp_dbg("write batch of %d regs", num);
for (i = 0; i < num; i++) { for (i = offset; i < offset + num; i++) {
data[offset++] = regs[i].reg; const struct aes_regwrite *regwrite = &wdata->regs[i];
data[offset++] = regs[i].value; data[data_offset++] = regwrite->reg;
data[data_offset++] = regwrite->value;
} }
r = libusb_bulk_transfer(dev->udev, &msg, &transferred, BULK_TIMEOUT); urbh = libusb_async_bulk_transfer(wdata->imgdev->udev, &msg,
g_free(data); write_regv_trf_complete, wdata, BULK_TIMEOUT);
if (r < 0) { if (!urbh) {
fp_err("bulk write error %d", r); g_free(data);
return r;
} else if ((unsigned int) transferred < alloc_size) {
fp_err("unexpected short write %d/%d", r, alloc_size);
return -EIO; return -EIO;
} }
return 0; return 0;
} }
int aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs, /* write the next batch of registers to be written, or if there are no more,
unsigned int num) * indicate completion to the caller */
static void continue_write_regv(struct write_regv_data *wdata)
{ {
unsigned int i; unsigned int offset = wdata->offset;
int skip = 0; unsigned int regs_remaining;
int add_offset = 0; unsigned int limit;
fp_dbg("write %d regs", num); unsigned int upper_bound;
int i;
for (i = 0; i < num; i += add_offset + skip) { int r;
int r, j;
int limit = MIN(num, i + MAX_REGWRITES_PER_REQUEST); /* skip all zeros and ensure there is still work to do */
skip = 0; while (TRUE) {
if (offset >= wdata->num_regs) {
if (!regs[i].reg) { fp_dbg("all registers written");
add_offset = 0; wdata->callback(wdata->imgdev, 0);
skip = 1; return;
continue;
} }
if (wdata->regs[offset].reg)
break;
offset++;
}
for (j = i; j < limit; j++) regs_remaining = wdata->num_regs - offset;
if (!regs[j].reg) { limit = MIN(regs_remaining, MAX_REGWRITES_PER_REQUEST);
skip = 1; upper_bound = offset + limit;
break;
}
add_offset = j - i; /* determine if we can write the entire of the regs at once, or if there
r = do_write_regv(dev, &regs[i], add_offset); * is a zero dividing things up */
if (r < 0) for (i = offset; i < offset + limit; i++)
return r; if (!wdata->regs[i].reg) {
upper_bound = i - 1;
break;
}
r = do_write_regv(wdata, upper_bound);
if (r < 0) {
wdata->callback(wdata->imgdev, r);
return;
} }
return 0; wdata->offset = upper_bound + 1;
}
/* write a load of registers to the device, combining multiple writes in a
* single URB up to a limit. insert writes to non-existent register 0 to force
* specific groups of writes to be separated by different URBs. */
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
unsigned int num_regs, aes_write_regv_cb callback)
{
struct write_regv_data *wdata = g_malloc(sizeof(*wdata));
fp_dbg("write %d regs", num_regs);
wdata->imgdev = dev;
wdata->num_regs = num_regs;
wdata->regs = regs;
wdata->offset = 0;
wdata->callback = callback;
continue_write_regv(wdata);
} }
void aes_assemble_image(unsigned char *input, size_t width, size_t height, void aes_assemble_image(unsigned char *input, size_t width, size_t height,
......
...@@ -27,8 +27,10 @@ struct aes_regwrite { ...@@ -27,8 +27,10 @@ struct aes_regwrite {
unsigned char value; unsigned char value;
}; };
int aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs, typedef void (*aes_write_regv_cb)(struct fp_img_dev *dev, int result);
unsigned int num);
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
unsigned int num_regs, aes_write_regv_cb callback);
void aes_assemble_image(unsigned char *input, size_t width, size_t height, void aes_assemble_image(unsigned char *input, size_t width, size_t height,
unsigned char *output); unsigned char *output);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment