aeslib: port to asynchronous model
This commit is contained in:
parent
3048b37176
commit
d731d5f3a3
2 changed files with 103 additions and 45 deletions
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* 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 @@
|
||||||
#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;
|
||||||
|
int r;
|
||||||
|
|
||||||
for (i = 0; i < num; i += add_offset + skip) {
|
/* skip all zeros and ensure there is still work to do */
|
||||||
int r, j;
|
while (TRUE) {
|
||||||
int limit = MIN(num, i + MAX_REGWRITES_PER_REQUEST);
|
if (offset >= wdata->num_regs) {
|
||||||
skip = 0;
|
fp_dbg("all registers written");
|
||||||
|
wdata->callback(wdata->imgdev, 0);
|
||||||
if (!regs[i].reg) {
|
return;
|
||||||
add_offset = 0;
|
|
||||||
skip = 1;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
if (wdata->regs[offset].reg)
|
||||||
for (j = i; j < limit; j++)
|
break;
|
||||||
if (!regs[j].reg) {
|
offset++;
|
||||||
skip = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_offset = j - i;
|
|
||||||
r = do_write_regv(dev, ®s[i], add_offset);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
regs_remaining = wdata->num_regs - offset;
|
||||||
|
limit = MIN(regs_remaining, MAX_REGWRITES_PER_REQUEST);
|
||||||
|
upper_bound = offset + limit;
|
||||||
|
|
||||||
|
/* determine if we can write the entire of the regs at once, or if there
|
||||||
|
* is a zero dividing things up */
|
||||||
|
for (i = offset; i < offset + limit; i++)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
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);
|
||||||
|
|
Loading…
Reference in a new issue