Update for libusb API rework

This commit is contained in:
Daniel Drake 2008-03-10 11:35:58 +00:00
parent 81a5d6d966
commit 4e884807a7
9 changed files with 601 additions and 489 deletions

View file

@ -46,22 +46,19 @@ static void continue_write_regv(struct write_regv_data *wdata);
/* libusb bulk callback for regv write completion transfer. continues the /* libusb bulk callback for regv write completion transfer. continues the
* transaction */ * transaction */
static void write_regv_trf_complete(libusb_dev_handle *devh, static void write_regv_trf_complete(struct libusb_transfer *transfer)
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; struct write_regv_data *wdata = transfer->user_data;
g_free(data); if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
libusb_urb_handle_free(urbh);
if (status != FP_URB_COMPLETED)
wdata->callback(wdata->imgdev, -EIO, wdata->user_data); wdata->callback(wdata->imgdev, -EIO, wdata->user_data);
else if (rqlength != actual_length) else if (transfer->length != transfer->actual_length)
wdata->callback(wdata->imgdev, -EPROTO, wdata->user_data); wdata->callback(wdata->imgdev, -EPROTO, wdata->user_data);
else else
continue_write_regv(wdata); continue_write_regv(wdata);
g_free(transfer->buffer);
libusb_free_transfer(transfer);
} }
/* write from wdata->offset to upper_bound (inclusive) of wdata->regs */ /* write from wdata->offset to upper_bound (inclusive) of wdata->regs */
@ -73,12 +70,13 @@ static int do_write_regv(struct write_regv_data *wdata, int upper_bound)
unsigned char *data = g_malloc(alloc_size); unsigned char *data = g_malloc(alloc_size);
unsigned int i; unsigned int i;
size_t data_offset = 0; size_t data_offset = 0;
struct libusb_urb_handle *urbh; struct libusb_transfer *transfer = libusb_alloc_transfer();
struct libusb_bulk_transfer msg = { int r;
.endpoint = EP_OUT,
.data = data, if (!transfer) {
.length = alloc_size, g_free(data);
}; return -ENOMEM;
}
for (i = offset; i < offset + num; i++) { for (i = offset; i < offset + num; i++) {
const struct aes_regwrite *regwrite = &wdata->regs[i]; const struct aes_regwrite *regwrite = &wdata->regs[i];
@ -86,14 +84,15 @@ static int do_write_regv(struct write_regv_data *wdata, int upper_bound)
data[data_offset++] = regwrite->value; data[data_offset++] = regwrite->value;
} }
urbh = libusb_async_bulk_transfer(wdata->imgdev->udev, &msg, libusb_fill_bulk_transfer(transfer, wdata->imgdev->udev, EP_OUT, data,
write_regv_trf_complete, wdata, BULK_TIMEOUT); alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT);
if (!urbh) { r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data); g_free(data);
return -EIO; libusb_free_transfer(transfer);
} }
return 0; return r;
} }
/* write the next batch of registers to be written, or if there are no more, /* write the next batch of registers to be written, or if there are no more,

View file

@ -41,7 +41,7 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb cb,
{ {
struct fp_driver *drv = ddev->drv; struct fp_driver *drv = ddev->drv;
struct fp_dev *dev; struct fp_dev *dev;
libusb_dev_handle *udevh; libusb_device_handle *udevh;
int r; int r;
fp_dbg(""); fp_dbg("");

View file

@ -352,11 +352,11 @@ static void register_drivers(void)
} }
} }
static struct fp_driver *find_supporting_driver(libusb_dev *udev, static struct fp_driver *find_supporting_driver(libusb_device *udev,
const struct usb_id **usb_id) const struct usb_id **usb_id)
{ {
GSList *elem = registered_drivers; GSList *elem = registered_drivers;
struct libusb_dev_descriptor *dsc = libusb_dev_get_descriptor(udev); struct libusb_device_descriptor *dsc = libusb_get_device_descriptor(udev);
do { do {
struct fp_driver *drv = elem->data; struct fp_driver *drv = elem->data;
@ -373,7 +373,7 @@ static struct fp_driver *find_supporting_driver(libusb_dev *udev,
return NULL; return NULL;
} }
static struct fp_dscv_dev *discover_dev(libusb_dev *udev) static struct fp_dscv_dev *discover_dev(libusb_device *udev)
{ {
const struct usb_id *usb_id; const struct usb_id *usb_id;
struct fp_driver *drv = find_supporting_driver(udev, &usb_id); struct fp_driver *drv = find_supporting_driver(udev, &usb_id);
@ -409,33 +409,40 @@ API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void)
{ {
GSList *tmplist = NULL; GSList *tmplist = NULL;
struct fp_dscv_dev **list; struct fp_dscv_dev **list;
struct libusb_dev *udev; libusb_device *udev;
libusb_device **devs;
int dscv_count = 0; int dscv_count = 0;
int r;
int i = 0;
if (registered_drivers == NULL) if (registered_drivers == NULL)
return NULL; return NULL;
libusb_find_devices(); r = libusb_get_device_list(&devs);
if (r < 0) {
fp_err("couldn't enumerate USB devices, error %d", r);
return NULL;
}
/* Check each device against each driver, temporarily storing successfully /* Check each device against each driver, temporarily storing successfully
* discovered devices in a GSList. * discovered devices in a GSList.
* *
* Quite inefficient but excusable as we'll only be dealing with small * Quite inefficient but excusable as we'll only be dealing with small
* sets of drivers against small sets of USB devices */ * sets of drivers against small sets of USB devices */
for (udev = libusb_get_devices(); udev; udev = libusb_dev_next(udev)) { while ((udev = devs[i++]) != NULL) {
struct fp_dscv_dev *ddev = discover_dev(udev); struct fp_dscv_dev *ddev = discover_dev(udev);
if (!ddev) if (!ddev)
continue; continue;
tmplist = g_slist_prepend(tmplist, (gpointer) ddev); tmplist = g_slist_prepend(tmplist, (gpointer) ddev);
dscv_count++; dscv_count++;
} }
/* Convert our temporary GSList into a standard NULL-terminated pointer /* Convert our temporary GSList into a standard NULL-terminated pointer
* array. */ * array. */
list = g_malloc(sizeof(*list) * (dscv_count + 1)); list = g_malloc(sizeof(*list) * (dscv_count + 1));
if (dscv_count > 0) { if (dscv_count > 0) {
GSList *elem = tmplist; GSList *elem = tmplist;
int i = 0; i = 0;
do { do {
list[i++] = elem->data; list[i++] = elem->data;
} while ((elem = g_slist_next(elem))); } while ((elem = g_slist_next(elem)));

View file

@ -79,48 +79,53 @@ struct aes2501_read_regs {
void *user_data; void *user_data;
}; };
static void read_regs_data_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void read_regs_data_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, unsigned char endpoint, int rqlength,
unsigned char *data, int actual_length, void *user_data)
{ {
struct aes2501_read_regs *rdata = user_data; struct aes2501_read_regs *rdata = transfer->user_data;
unsigned char *retdata = NULL; unsigned char *retdata = NULL;
int r; int r;
if (status != FP_URB_COMPLETED) { if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
r = -EIO; r = -EIO;
} else if (rqlength != actual_length) { } else if (transfer->length != transfer->actual_length) {
r = -EPROTO; r = -EPROTO;
} else { } else {
r = 0; r = 0;
retdata = data; retdata = transfer->buffer;
} }
rdata->callback(rdata->dev, r, retdata, rdata->user_data); rdata->callback(rdata->dev, r, retdata, rdata->user_data);
libusb_urb_handle_free(urbh);
g_free(data);
g_free(rdata); g_free(rdata);
g_free(transfer->buffer);
libusb_free_transfer(transfer);
} }
static void read_regs_rq_cb(struct fp_img_dev *dev, int result, void *user_data) static void read_regs_rq_cb(struct fp_img_dev *dev, int result, void *user_data)
{ {
struct aes2501_read_regs *rdata = user_data; struct aes2501_read_regs *rdata = user_data;
struct libusb_urb_handle *urbh; struct libusb_transfer *transfer;
struct libusb_bulk_transfer trf = { unsigned char *data;
.endpoint = EP_IN, int r;
.length = 126,
};
g_free(rdata->regwrite); g_free(rdata->regwrite);
if (result != 0) if (result != 0)
goto err; goto err;
trf.data = g_malloc(trf.length); transfer = libusb_alloc_transfer();
urbh = libusb_async_bulk_transfer(dev->udev, &trf, read_regs_data_cb, if (!transfer) {
rdata, BULK_TIMEOUT); result = -ENOMEM;
if (!urbh) { goto err;
g_free(trf.data); }
result = EIO;
data = g_malloc(126);
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 126,
read_regs_data_cb, rdata, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
result = -EIO;
goto err; goto err;
} }
@ -179,40 +184,43 @@ static void generic_write_regv_cb(struct fp_img_dev *dev, int result,
} }
/* check that read succeeded but ignore all data */ /* check that read succeeded but ignore all data */
static void generic_ignore_data_cb(libusb_dev_handle *devh, static void generic_ignore_data_cb(struct libusb_transfer *transfer)
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 fpi_ssm *ssm = user_data; struct fpi_ssm *ssm = transfer->user_data;
libusb_urb_handle_free(urbh); if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
g_free(data);
if (status != FP_URB_COMPLETED)
fpi_ssm_mark_aborted(ssm, -EIO); fpi_ssm_mark_aborted(ssm, -EIO);
else if (rqlength != actual_length) else if (transfer->length != transfer->actual_length)
fpi_ssm_mark_aborted(ssm, -EPROTO); fpi_ssm_mark_aborted(ssm, -EPROTO);
else else
fpi_ssm_next_state(ssm); fpi_ssm_next_state(ssm);
g_free(transfer->buffer);
libusb_free_transfer(transfer);
} }
/* read the specified number of bytes from the IN endpoint but throw them /* read the specified number of bytes from the IN endpoint but throw them
* away, then increment the SSM */ * away, then increment the SSM */
static void generic_read_ignore_data(struct fpi_ssm *ssm, size_t bytes) static void generic_read_ignore_data(struct fpi_ssm *ssm, size_t bytes)
{ {
struct libusb_urb_handle *urbh; struct libusb_transfer *transfer = libusb_alloc_transfer();
struct libusb_bulk_transfer trf = { unsigned char *data;
.endpoint = EP_IN, int r;
.data = g_malloc(bytes),
.length = bytes,
};
urbh = libusb_async_bulk_transfer(ssm->dev->udev, &trf, if (!transfer) {
fpi_ssm_mark_aborted(ssm, -ENOMEM);
return;
}
data = g_malloc(bytes);
libusb_fill_bulk_transfer(transfer, ssm->dev->udev, EP_IN, data, bytes,
generic_ignore_data_cb, ssm, BULK_TIMEOUT); generic_ignore_data_cb, ssm, BULK_TIMEOUT);
if (!urbh) {
g_free(trf.data); r = libusb_submit_transfer(transfer);
fpi_ssm_mark_aborted(ssm, -EIO); if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
fpi_ssm_mark_aborted(ssm, r);
} }
} }
@ -382,19 +390,17 @@ static const struct aes_regwrite finger_det_reqs[] = {
static void start_finger_detection(struct fp_img_dev *dev); static void start_finger_detection(struct fp_img_dev *dev);
static void finger_det_data_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void finger_det_data_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, unsigned char endpoint,
int rqlength, unsigned char *data, int actual_length, void *user_data)
{ {
struct fp_img_dev *dev = user_data; struct fp_img_dev *dev = transfer->user_data;
unsigned char *data = transfer->buffer;
int i; int i;
int sum = 0; int sum = 0;
libusb_urb_handle_free(urbh); if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
if (status != FP_URB_COMPLETED) {
fpi_imgdev_session_error(dev, -EIO); fpi_imgdev_session_error(dev, -EIO);
goto out; goto out;
} else if (rqlength != actual_length) { } else if (transfer->length != transfer->actual_length) {
fpi_imgdev_session_error(dev, -EPROTO); fpi_imgdev_session_error(dev, -EPROTO);
goto out; goto out;
} }
@ -413,28 +419,36 @@ static void finger_det_data_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh,
out: out:
g_free(data); g_free(data);
libusb_free_transfer(transfer);
} }
static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, static void finger_det_reqs_cb(struct fp_img_dev *dev, int result,
void *user_data) void *user_data)
{ {
struct libusb_urb_handle *urbh; struct libusb_transfer *transfer;
struct libusb_bulk_transfer trf = { unsigned char *data;
.endpoint = EP_IN, int r;
.length = 20,
};
if (result) { if (result) {
fpi_imgdev_session_error(dev, result); fpi_imgdev_session_error(dev, result);
return; return;
} }
trf.data = g_malloc(trf.length); transfer = libusb_alloc_transfer();
urbh = libusb_async_bulk_transfer(dev->udev, &trf, finger_det_data_cb, if (!transfer) {
dev, BULK_TIMEOUT); fpi_imgdev_session_error(dev, -ENOMEM);
if (!urbh) { return;
g_free(trf.data); }
fpi_imgdev_session_error(dev, -EIO);
data = g_malloc(20);
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 20,
finger_det_data_cb, dev, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
fpi_imgdev_session_error(dev, r);
} }
} }
@ -527,23 +541,20 @@ enum capture_states {
CAPTURE_NUM_STATES, CAPTURE_NUM_STATES,
}; };
static void capture_read_strip_cb(libusb_dev_handle *devh, static void capture_read_strip_cb(struct libusb_transfer *transfer)
libusb_urb_handle *urbh, enum libusb_urb_cb_status status,
unsigned char endpoint, int rqlength, unsigned char *data,
int actual_length, void *user_data)
{ {
unsigned char *stripdata; unsigned char *stripdata;
struct fpi_ssm *ssm = user_data; struct fpi_ssm *ssm = transfer->user_data;
struct fp_img_dev *dev = ssm->priv; struct fp_img_dev *dev = ssm->priv;
struct aes2501_dev *aesdev = dev->priv; struct aes2501_dev *aesdev = dev->priv;
unsigned char *data = transfer->buffer;
int sum; int sum;
int threshold; int threshold;
libusb_urb_handle_free(urbh); if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
if (status != FP_URB_COMPLETED) {
fpi_ssm_mark_aborted(ssm, -EIO); fpi_ssm_mark_aborted(ssm, -EIO);
goto out; goto out;
} else if (rqlength != actual_length) { } else if (transfer->length != transfer->actual_length) {
fpi_ssm_mark_aborted(ssm, -EPROTO); fpi_ssm_mark_aborted(ssm, -EPROTO);
goto out; goto out;
} }
@ -587,12 +598,14 @@ static void capture_read_strip_cb(libusb_dev_handle *devh,
out: out:
g_free(data); g_free(data);
libusb_free_transfer(transfer);
} }
static void capture_run_state(struct fpi_ssm *ssm) static void capture_run_state(struct fpi_ssm *ssm)
{ {
struct fp_img_dev *dev = ssm->priv; struct fp_img_dev *dev = ssm->priv;
struct aes2501_dev *aesdev = dev->priv; struct aes2501_dev *aesdev = dev->priv;
int r;
switch (ssm->cur_state) { switch (ssm->cur_state) {
case CAPTURE_WRITE_REQS_1: case CAPTURE_WRITE_REQS_1:
@ -617,17 +630,23 @@ static void capture_run_state(struct fpi_ssm *ssm)
generic_write_regv_cb, ssm); generic_write_regv_cb, ssm);
break; break;
case CAPTURE_READ_STRIP: ; case CAPTURE_READ_STRIP: ;
struct libusb_urb_handle *urbh; struct libusb_transfer *transfer = libusb_alloc_transfer();
struct libusb_bulk_transfer trf = { unsigned char *data;
.endpoint = EP_IN,
.data = g_malloc(1705), if (!transfer) {
.length = 1705, fpi_ssm_mark_aborted(ssm, -ENOMEM);
}; break;
urbh = libusb_async_bulk_transfer(dev->udev, &trf, }
data = g_malloc(1705);
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 1705,
capture_read_strip_cb, ssm, BULK_TIMEOUT); capture_read_strip_cb, ssm, BULK_TIMEOUT);
if (!urbh) {
g_free(trf.data); r = libusb_submit_transfer(transfer);
fpi_ssm_mark_aborted(ssm, -EIO); if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
fpi_ssm_mark_aborted(ssm, r);
} }
break; break;
}; };

View file

@ -35,7 +35,7 @@
#define SUBARRAY_LEN 768 #define SUBARRAY_LEN 768
struct aes4k_dev { struct aes4k_dev {
libusb_urb_handle *img_trf; struct libusb_transfer *img_trf;
}; };
static const struct aes_regwrite init_reqs[] = { static const struct aes_regwrite init_reqs[] = {
@ -115,22 +115,20 @@ static const struct aes_regwrite init_reqs[] = {
static void do_capture(struct fp_img_dev *dev); static void do_capture(struct fp_img_dev *dev);
static void img_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void img_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, unsigned char endpoint,
int rqlength, unsigned char *data, int actual_length, void *user_data)
{ {
struct fp_img_dev *dev = user_data; struct fp_img_dev *dev = transfer->user_data;
struct aes4k_dev *aesdev = dev->priv; struct aes4k_dev *aesdev = dev->priv;
unsigned char *ptr = data; unsigned char *ptr = transfer->buffer;
struct fp_img *img; struct fp_img *img;
int i; int i;
if (status == FP_URB_CANCELLED) { if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
goto err; goto err;
} else if (status != FP_URB_COMPLETED) { } else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fpi_imgdev_session_error(dev, -EIO); fpi_imgdev_session_error(dev, -EIO);
goto err; goto err;
} else if (rqlength != actual_length) { } else if (transfer->length != transfer->actual_length) {
fpi_imgdev_session_error(dev, -EPROTO); fpi_imgdev_session_error(dev, -EPROTO);
goto err; goto err;
} }
@ -155,25 +153,33 @@ static void img_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh,
do_capture(dev); do_capture(dev);
err: err:
g_free(data); g_free(transfer->buffer);
aesdev->img_trf = NULL; aesdev->img_trf = NULL;
libusb_urb_handle_free(urbh); libusb_free_transfer(transfer);
} }
static void do_capture(struct fp_img_dev *dev) static void do_capture(struct fp_img_dev *dev)
{ {
struct aes4k_dev *aesdev = dev->priv; struct aes4k_dev *aesdev = dev->priv;
struct libusb_bulk_transfer trf = { unsigned char *data;
.endpoint = EP_IN, int r;
.length = DATA_BUFLEN,
.data = g_malloc(DATA_BUFLEN),
};
aesdev->img_trf = libusb_async_bulk_transfer(dev->udev, &trf, img_cb, dev, aesdev->img_trf = libusb_alloc_transfer();
0);
if (!aesdev->img_trf) { if (!aesdev->img_trf) {
g_free(trf.data);
fpi_imgdev_session_error(dev, -EIO); fpi_imgdev_session_error(dev, -EIO);
return;
}
data = g_malloc(DATA_BUFLEN);
libusb_fill_bulk_transfer(aesdev->img_trf, dev->udev, EP_IN, data,
DATA_BUFLEN, img_cb, dev, 0);
r = libusb_submit_transfer(aesdev->img_trf);
if (r < 0) {
g_free(data);
libusb_free_transfer(aesdev->img_trf);
aesdev->img_trf = NULL;
fpi_imgdev_session_error(dev, r);
} }
} }
@ -198,7 +204,7 @@ static void dev_deactivate(struct fp_img_dev *dev)
* from deactivation, otherwise app may legally exit before we've * from deactivation, otherwise app may legally exit before we've
* cleaned up */ * cleaned up */
if (aesdev->img_trf) if (aesdev->img_trf)
libusb_urb_handle_cancel(dev->udev, aesdev->img_trf); libusb_cancel_transfer(aesdev->img_trf);
fpi_imgdev_deactivate_complete(dev); fpi_imgdev_deactivate_complete(dev);
} }

View file

@ -133,10 +133,11 @@ static uint16_t udf_crc(unsigned char *buffer, size_t size)
#define CMD_SEQ_INCREMENT 0x10 #define CMD_SEQ_INCREMENT 0x10
static void fill_send_cmd_urb(struct libusb_bulk_transfer *msg, static struct libusb_transfer *alloc_send_cmd_transfer(struct fp_dev *dev,
unsigned char seq_a, unsigned char seq_b, const unsigned char *data, unsigned char seq_a, unsigned char seq_b, const unsigned char *data,
uint16_t len) uint16_t len, libusb_transfer_cb_fn callback, void *user_data)
{ {
struct libusb_transfer *transfer = libusb_alloc_transfer();
uint16_t crc; uint16_t crc;
/* 9 bytes extra for: 4 byte 'Ciao', 1 byte A, 1 byte B | lenHI, /* 9 bytes extra for: 4 byte 'Ciao', 1 byte A, 1 byte B | lenHI,
@ -144,15 +145,15 @@ static void fill_send_cmd_urb(struct libusb_bulk_transfer *msg,
size_t urblen = len + 9; size_t urblen = len + 9;
unsigned char *buf; unsigned char *buf;
if (!transfer)
return NULL;
if (!data && len > 0) { if (!data && len > 0) {
fp_err("len>0 but no data?"); fp_err("len>0 but no data?");
return; return NULL;
} }
msg->endpoint = EP_OUT;
msg->length = urblen;
buf = g_malloc(urblen); buf = g_malloc(urblen);
msg->data = buf;
/* Write header */ /* Write header */
strncpy(buf, "Ciao", 4); strncpy(buf, "Ciao", 4);
@ -169,17 +170,22 @@ static void fill_send_cmd_urb(struct libusb_bulk_transfer *msg,
crc = GUINT16_TO_BE(udf_crc(buf + 4, urblen - 6)); crc = GUINT16_TO_BE(udf_crc(buf + 4, urblen - 6));
buf[urblen - 2] = crc >> 8; buf[urblen - 2] = crc >> 8;
buf[urblen - 1] = crc & 0xff; buf[urblen - 1] = crc & 0xff;
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, buf, urblen,
callback, user_data, TIMEOUT);
return transfer;
} }
static void fill_send_cmd28_urb(struct fp_dev *dev, static struct libusb_transfer *alloc_send_cmd28_transfer(struct fp_dev *dev,
struct libusb_bulk_transfer *msg, unsigned char subcmd, unsigned char subcmd, const unsigned char *data, uint16_t innerlen,
const unsigned char *data, uint16_t innerlen) libusb_transfer_cb_fn callback, void *user_data)
{ {
uint16_t _innerlen = innerlen; uint16_t _innerlen = innerlen;
size_t len = innerlen + 6; size_t len = innerlen + 6;
unsigned char *buf = g_malloc0(len); unsigned char *buf = g_malloc0(len);
struct upekts_dev *upekdev = dev->priv; struct upekts_dev *upekdev = dev->priv;
uint8_t seq = upekdev->seq + CMD_SEQ_INCREMENT; uint8_t seq = upekdev->seq + CMD_SEQ_INCREMENT;
struct libusb_transfer *ret;
fp_dbg("seq=%02x subcmd=%02x with %d bytes of data", seq, subcmd, innerlen); fp_dbg("seq=%02x subcmd=%02x with %d bytes of data", seq, subcmd, innerlen);
@ -190,17 +196,19 @@ static void fill_send_cmd28_urb(struct fp_dev *dev,
buf[5] = subcmd; buf[5] = subcmd;
memcpy(buf + 6, data, innerlen); memcpy(buf + 6, data, innerlen);
fill_send_cmd_urb(msg, 0, seq, buf, len); ret = alloc_send_cmd_transfer(dev, 0, seq, buf, len, callback, user_data);
upekdev->seq = seq; upekdev->seq = seq;
g_free(buf); g_free(buf);
return ret;
} }
static void fill_send_cmdresponse_urb(struct libusb_bulk_transfer *msg, static struct libusb_transfer *alloc_send_cmdresponse_transfer(
unsigned char seq, const unsigned char *data, uint8_t len) struct fp_dev *dev, unsigned char seq, const unsigned char *data,
uint8_t len, libusb_transfer_cb_fn callback, void *user_data)
{ {
fp_dbg("seq=%02x len=%d", seq, len); fp_dbg("seq=%02x len=%d", seq, len);
fill_send_cmd_urb(msg, seq, 0, data, len); return alloc_send_cmd_transfer(dev, seq, 0, data, len, callback, user_data);
} }
enum read_msg_status { enum read_msg_status {
@ -224,12 +232,12 @@ static int __read_msg_async(struct read_msg_data *udata);
#define READ_MSG_DATA_CB_ERR(udata) (udata)->callback((udata)->dev, \ #define READ_MSG_DATA_CB_ERR(udata) (udata)->callback((udata)->dev, \
READ_MSG_ERROR, 0, 0, NULL, 0, (udata)->user_data) READ_MSG_ERROR, 0, 0, NULL, 0, (udata)->user_data)
static void busy_ack_sent_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void busy_ack_sent_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, unsigned char endpoint, int rqlength,
unsigned char *data, int actual_length, void *_data)
{ {
struct read_msg_data *udata = (struct read_msg_data *) _data; struct read_msg_data *udata = transfer->user_data;
if (status != FP_URB_COMPLETED || rqlength != actual_length) {
if (transfer->status != LIBUSB_TRANSFER_COMPLETED ||
transfer->length != transfer->actual_length) {
READ_MSG_DATA_CB_ERR(udata); READ_MSG_DATA_CB_ERR(udata);
g_free(udata); g_free(udata);
} else { } else {
@ -239,22 +247,25 @@ static void busy_ack_sent_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh,
g_free(udata); g_free(udata);
} }
} }
libusb_urb_handle_free(urbh); libusb_free_transfer(transfer);
} }
static int busy_ack_retry_read(struct read_msg_data *udata) static int busy_ack_retry_read(struct read_msg_data *udata)
{ {
struct libusb_bulk_transfer msg; struct libusb_transfer *transfer;
libusb_urb_handle *urbh; int r;
fill_send_cmdresponse_urb(&msg, 0x09, NULL, 0); transfer = alloc_send_cmdresponse_transfer(udata->dev, 0x09, NULL, 0,
urbh = libusb_async_bulk_transfer(udata->dev->udev, &msg, busy_ack_sent_cb, busy_ack_sent_cb, udata);
udata, TIMEOUT); if (!transfer)
if (!urbh) { return -ENOMEM;
g_free(msg.data);
return -EIO; r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(transfer->buffer);
libusb_free_transfer(transfer);
} }
return 0; return r;
} }
/* Returns 0 if message was handled, 1 if it was a device-busy message, and /* Returns 0 if message was handled, 1 if it was a device-busy message, and
@ -333,20 +344,19 @@ static int __handle_incoming_msg(struct read_msg_data *udata,
return 0; return 0;
} }
static void read_msg_extend_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void read_msg_extend_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, unsigned char endpoint, int rqlength,
unsigned char *data, int actual_length, void *user_data)
{ {
struct read_msg_data *udata = user_data; struct read_msg_data *udata = transfer->user_data;
unsigned char *buf = data - MSG_READ_BUF_SIZE; unsigned char *buf = transfer->buffer - MSG_READ_BUF_SIZE;
int handle_result = 0; int handle_result = 0;
if (status != FP_URB_COMPLETED) { if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fp_err("extended msg read failed, code %d", status); fp_err("extended msg read failed, code %d", transfer->status);
goto err; goto err;
} }
if (actual_length < rqlength) { if (transfer->actual_length < transfer->length) {
fp_err("extended msg short read (%d/%d)", actual_length, rqlength); fp_err("extended msg short read (%d/%d)", transfer->actual_length,
transfer->length);
goto err; goto err;
} }
@ -361,23 +371,22 @@ out:
if (handle_result != 1) if (handle_result != 1)
g_free(udata); g_free(udata);
g_free(buf); g_free(buf);
libusb_urb_handle_free(urbh); libusb_free_transfer(transfer);
} }
static void read_msg_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void read_msg_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, unsigned char endpoint,
int rqlength, unsigned char *data, int actual_length, void *user_data)
{ {
struct read_msg_data *udata = user_data; struct read_msg_data *udata = transfer->user_data;
unsigned char *data = transfer->buffer;
uint16_t len; uint16_t len;
int handle_result = 0; int handle_result = 0;
if (status != FP_URB_COMPLETED) { if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fp_err("async msg read failed, code %d", status); fp_err("async msg read failed, code %d", transfer->status);
goto err; goto err;
} }
if (actual_length < 9) { if (transfer->actual_length < 9) {
fp_err("async msg read too short (%d)", actual_length); fp_err("async msg read too short (%d)", transfer->actual_length);
goto err; goto err;
} }
@ -387,11 +396,12 @@ static void read_msg_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh,
} }
len = GUINT16_FROM_LE(((data[5] & 0xf) << 8) | data[6]); len = GUINT16_FROM_LE(((data[5] & 0xf) << 8) | data[6]);
if (actual_length != MSG_READ_BUF_SIZE && (len + 9) > actual_length) { if (transfer->actual_length != MSG_READ_BUF_SIZE
&& (len + 9) > transfer->actual_length) {
/* Check that the length claimed inside the message is in line with /* Check that the length claimed inside the message is in line with
* the amount of data that was transferred over USB. */ * the amount of data that was transferred over USB. */
fp_err("msg didn't include enough data, expected=%d recv=%d", fp_err("msg didn't include enough data, expected=%d recv=%d",
len + 9, actual_length); len + 9, transfer->actual_length);
goto err; goto err;
} }
@ -400,22 +410,26 @@ static void read_msg_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh,
* to read the remainder. This is handled below. */ * to read the remainder. This is handled below. */
if (len > MAX_DATA_IN_READ_BUF) { if (len > MAX_DATA_IN_READ_BUF) {
int needed = len - MAX_DATA_IN_READ_BUF; int needed = len - MAX_DATA_IN_READ_BUF;
libusb_urb_handle *eurbh; struct libusb_transfer *etransfer = libusb_alloc_transfer();
struct libusb_bulk_transfer extend_msg = { int r;
.endpoint = EP_IN,
.length = needed, if (!transfer)
}; goto err;
fp_dbg("didn't fit in buffer, need to extend by %d bytes", needed); fp_dbg("didn't fit in buffer, need to extend by %d bytes", needed);
data = g_realloc((gpointer) data, MSG_READ_BUF_SIZE + needed); data = g_realloc((gpointer) data, MSG_READ_BUF_SIZE + needed);
extend_msg.data = data + MSG_READ_BUF_SIZE;
eurbh = libusb_async_bulk_transfer(udata->dev->udev, &extend_msg, libusb_fill_bulk_transfer(etransfer, udata->dev->udev, EP_IN,
read_msg_extend_cb, udata, TIMEOUT); data + MSG_READ_BUF_SIZE, needed, read_msg_extend_cb, udata,
if (!eurbh) { TIMEOUT);
r = libusb_submit_transfer(etransfer);
if (r < 0) {
fp_err("extended read submission failed"); fp_err("extended read submission failed");
/* FIXME memory leak here? */
goto err; goto err;
} }
libusb_urb_handle_free(urbh); libusb_free_transfer(transfer);
return; return;
} }
@ -427,7 +441,7 @@ static void read_msg_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh,
err: err:
READ_MSG_DATA_CB_ERR(udata); READ_MSG_DATA_CB_ERR(udata);
out: out:
libusb_urb_handle_free(urbh); libusb_free_transfer(transfer);
if (handle_result != 1) if (handle_result != 1)
g_free(udata); g_free(udata);
g_free(data); g_free(data);
@ -436,18 +450,23 @@ out:
static int __read_msg_async(struct read_msg_data *udata) static int __read_msg_async(struct read_msg_data *udata)
{ {
unsigned char *buf = g_malloc(MSG_READ_BUF_SIZE); unsigned char *buf = g_malloc(MSG_READ_BUF_SIZE);
struct libusb_bulk_transfer msg = { struct libusb_transfer *transfer = libusb_alloc_transfer();
.endpoint = EP_IN, int r;
.data = buf,
.length = MSG_READ_BUF_SIZE, if (!transfer) {
};
libusb_urb_handle *urbh = libusb_async_bulk_transfer(udata->dev->udev, &msg,
read_msg_cb, udata, TIMEOUT);
if (!urbh) {
g_free(buf); g_free(buf);
return -EIO; return -ENOMEM;
} }
return 0;
libusb_fill_bulk_transfer(transfer, udata->dev->udev, EP_IN, buf,
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;
} }
static int read_msg_async(struct fp_dev *dev, read_msg_cb_fn callback, static int read_msg_async(struct fp_dev *dev, read_msg_cb_fn callback,
@ -613,16 +632,16 @@ static void read_msg03_cb(struct fp_dev *dev, enum read_msg_status status,
initsm_read_msg_cmd_cb((struct fpi_ssm *) user_data, status, 3, seq); initsm_read_msg_cmd_cb((struct fpi_ssm *) user_data, status, 3, seq);
} }
static void ctrl400_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void ctrl400_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, struct libusb_ctrl_setup *setup,
unsigned char *data, int actual_length, void *user_data)
{ {
struct fpi_ssm *ssm = user_data; struct fpi_ssm *ssm = transfer->user_data;
if (status == FP_URB_COMPLETED) /* FIXME check length? */
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
fpi_ssm_next_state(ssm); fpi_ssm_next_state(ssm);
else else
fpi_ssm_mark_aborted(ssm, -1); fpi_ssm_mark_aborted(ssm, -1);
libusb_urb_handle_free(urbh); g_free(transfer->buffer);
libusb_free_transfer(transfer);
} }
static void initsm_read_msg_handler(struct fpi_ssm *ssm, static void initsm_read_msg_handler(struct fpi_ssm *ssm,
@ -635,35 +654,40 @@ static void initsm_read_msg_handler(struct fpi_ssm *ssm,
} }
} }
static void initsm_send_msg_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void initsm_send_msg_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, unsigned char endpoint,
int rqlength, unsigned char *data, int actual_length, void *user_data)
{ {
struct fpi_ssm *ssm = user_data; struct fpi_ssm *ssm = transfer->user_data;
if (status == FP_URB_COMPLETED && rqlength == actual_length) { if (transfer->status == LIBUSB_TRANSFER_COMPLETED
&& transfer->length == transfer->actual_length) {
fp_dbg("state %d completed", ssm->cur_state); fp_dbg("state %d completed", ssm->cur_state);
fpi_ssm_next_state(ssm); fpi_ssm_next_state(ssm);
} else { } else {
fp_err("failed, state=%d rqlength=%d actual_length=%d", ssm->cur_state, fp_err("failed, state=%d rqlength=%d actual_length=%d", ssm->cur_state,
rqlength, actual_length); transfer->length, transfer->actual_length);
fpi_ssm_mark_aborted(ssm, -1); fpi_ssm_mark_aborted(ssm, -1);
} }
libusb_urb_handle_free(urbh); libusb_free_transfer(transfer);
} }
static void initsm_send_msg28_handler(struct fpi_ssm *ssm, static void initsm_send_msg28_handler(struct fpi_ssm *ssm,
unsigned char subcmd, const unsigned char *data, uint16_t innerlen) unsigned char subcmd, const unsigned char *data, uint16_t innerlen)
{ {
struct fp_dev *dev = ssm->dev; struct fp_dev *dev = ssm->dev;
struct libusb_urb_handle *urbh; struct libusb_transfer *transfer;
struct libusb_bulk_transfer trf; int r;
fill_send_cmd28_urb(dev, &trf, subcmd, data, innerlen); transfer = alloc_send_cmd28_transfer(dev, subcmd, data, innerlen,
urbh = libusb_async_bulk_transfer(dev->udev, &trf, initsm_send_msg_cb, initsm_send_msg_cb, ssm);
ssm, TIMEOUT); if (!transfer) {
if (!urbh) { fpi_ssm_mark_aborted(ssm, -ENOMEM);
fp_err("urb submission failed in state %d", ssm->cur_state); return;
g_free(trf.data); }
r = libusb_submit_transfer(transfer);
if (r < 0) {
fp_err("urb submission failed error %d in state %d", r, ssm->cur_state);
g_free(transfer->buffer);
libusb_free_transfer(transfer);
fpi_ssm_mark_aborted(ssm, -EIO); fpi_ssm_mark_aborted(ssm, -EIO);
} }
} }
@ -672,38 +696,48 @@ static void initsm_run_state(struct fpi_ssm *ssm)
{ {
struct fp_dev *dev = ssm->dev; struct fp_dev *dev = ssm->dev;
struct upekts_dev *upekdev = dev->priv; struct upekts_dev *upekdev = dev->priv;
struct libusb_urb_handle *urbh; struct libusb_transfer *transfer;
int r;
switch (ssm->cur_state) { switch (ssm->cur_state) {
case WRITE_CTRL400: ; case WRITE_CTRL400: ;
unsigned char dummy = 0x10; unsigned char *data;
struct libusb_control_transfer ctrl400_trf = {
.requesttype = LIBUSB_TYPE_VENDOR | LIBUSB_RECIP_DEVICE,
.request = 0x0c,
.value = 0x0100,
.index = 0x0400,
.length = sizeof(dummy),
.data = &dummy,
};
urbh = libusb_async_control_transfer(ssm->dev->udev, &ctrl400_trf, transfer = libusb_alloc_transfer();
if (!transfer) {
fpi_ssm_mark_aborted(ssm, -ENOMEM);
break;
}
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
libusb_fill_control_setup(data,
LIBUSB_TYPE_VENDOR | LIBUSB_RECIP_DEVICE, 0x0c, 0x100, 0x0400, 1);
libusb_fill_control_transfer(transfer, ssm->dev->udev, data,
ctrl400_cb, ssm, TIMEOUT); ctrl400_cb, ssm, TIMEOUT);
if (!urbh)
fpi_ssm_mark_aborted(ssm, -1); r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
fpi_ssm_mark_aborted(ssm, r);
}
break; break;
case READ_MSG03: case READ_MSG03:
initsm_read_msg_handler(ssm, read_msg03_cb); initsm_read_msg_handler(ssm, read_msg03_cb);
break; break;
case SEND_RESP03: ; case SEND_RESP03: ;
struct libusb_bulk_transfer resp03_trf; 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;
}
fill_send_cmdresponse_urb(&resp03_trf, ++upekdev->seq, init_resp03, r = libusb_submit_transfer(transfer);
sizeof(init_resp03)); if (r < 0) {
urbh = libusb_async_bulk_transfer(dev->udev, &resp03_trf, g_free(transfer->buffer);
initsm_send_msg_cb, ssm, TIMEOUT); libusb_free_transfer(transfer);
if (!urbh) { fpi_ssm_mark_aborted(ssm, r);
g_free(resp03_trf.data);
fpi_ssm_mark_aborted(ssm, -EIO);
} }
break; break;
case READ_MSG05: case READ_MSG05:
@ -756,18 +790,16 @@ enum deinitsm_states {
DEINITSM_NUM_STATES, DEINITSM_NUM_STATES,
}; };
static void send_resp07_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void send_resp07_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, unsigned char endpoint,
int rqlength, unsigned char *data, int actual_length, void *user_data)
{ {
struct fpi_ssm *ssm = user_data; struct fpi_ssm *ssm = transfer->user_data;
if (status != FP_URB_COMPLETED) if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
fpi_ssm_mark_aborted(ssm, -EIO); fpi_ssm_mark_aborted(ssm, -EIO);
else if (rqlength != actual_length) else if (transfer->length != transfer->actual_length)
fpi_ssm_mark_aborted(ssm, -EPROTO); fpi_ssm_mark_aborted(ssm, -EPROTO);
else else
fpi_ssm_next_state(ssm); fpi_ssm_next_state(ssm);
libusb_urb_handle_free(urbh); libusb_free_transfer(transfer);
} }
static void read_msg01_cb(struct fp_dev *dev, enum read_msg_status status, static void read_msg01_cb(struct fp_dev *dev, enum read_msg_status status,
@ -798,23 +830,29 @@ static void read_msg01_cb(struct fp_dev *dev, enum read_msg_status status,
static void deinitsm_state_handler(struct fpi_ssm *ssm) static void deinitsm_state_handler(struct fpi_ssm *ssm)
{ {
struct fp_dev *dev = ssm->dev; struct fp_dev *dev = ssm->dev;
int r;
switch (ssm->cur_state) { switch (ssm->cur_state) {
case SEND_RESP07: ; case SEND_RESP07: ;
struct libusb_bulk_transfer msg; struct libusb_transfer *transfer;
struct libusb_urb_handle *urbh;
unsigned char dummy = 0; unsigned char dummy = 0;
fill_send_cmdresponse_urb(&msg, 0x07, &dummy, 1); transfer = alloc_send_cmdresponse_transfer(dev, 0x07, &dummy, 1,
urbh = libusb_async_bulk_transfer(dev->udev, &msg, send_resp07_cb, ssm, send_resp07_cb, ssm);
TIMEOUT); if (!transfer) {
if (!urbh) { fpi_ssm_mark_aborted(ssm, -ENOMEM);
g_free(msg.data); break;
fpi_ssm_mark_aborted(ssm, -EIO); }
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(transfer->buffer);
libusb_free_transfer(transfer);
fpi_ssm_mark_aborted(ssm, r);
} }
break; break;
case READ_MSG01: ; case READ_MSG01: ;
int r = read_msg_async(dev, read_msg01_cb, ssm); r = read_msg_async(dev, read_msg01_cb, ssm);
if (r < 0) if (r < 0)
fpi_ssm_mark_aborted(ssm, r); fpi_ssm_mark_aborted(ssm, r);
break; break;
@ -882,19 +920,16 @@ static void enroll_start_sm_cb_initsm(struct fpi_ssm *initsm)
} }
/* called when enroll init URB has completed */ /* called when enroll init URB has completed */
static void enroll_start_sm_cb_init(libusb_dev_handle *devh, static void enroll_start_sm_cb_init(struct libusb_transfer *transfer)
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 fpi_ssm *ssm = user_data; struct fpi_ssm *ssm = transfer->user_data;
if (status != FP_URB_COMPLETED) if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
fpi_ssm_mark_aborted(ssm, -EIO); fpi_ssm_mark_aborted(ssm, -EIO);
else if (rqlength != actual_length) else if (transfer->length != transfer->actual_length)
fpi_ssm_mark_aborted(ssm, -EPROTO); fpi_ssm_mark_aborted(ssm, -EPROTO);
else else
fpi_ssm_next_state(ssm); fpi_ssm_next_state(ssm);
libusb_urb_handle_free(urbh); libusb_free_transfer(transfer);
} }
static void enroll_start_sm_cb_msg28(struct fp_dev *dev, static void enroll_start_sm_cb_msg28(struct fp_dev *dev,
@ -923,6 +958,7 @@ static void enroll_start_sm_cb_msg28(struct fp_dev *dev,
static void enroll_start_sm_run_state(struct fpi_ssm *ssm) static void enroll_start_sm_run_state(struct fpi_ssm *ssm)
{ {
struct fp_dev *dev = ssm->dev; struct fp_dev *dev = ssm->dev;
int r;
switch (ssm->cur_state) { switch (ssm->cur_state) {
case RUN_INITSM: ; case RUN_INITSM: ;
@ -931,14 +967,19 @@ static void enroll_start_sm_run_state(struct fpi_ssm *ssm)
fpi_ssm_start(initsm, enroll_start_sm_cb_initsm); fpi_ssm_start(initsm, enroll_start_sm_cb_initsm);
break; break;
case ENROLL_INIT: ; case ENROLL_INIT: ;
struct libusb_bulk_transfer msg; struct libusb_transfer *transfer;
struct libusb_urb_handle *urbh; transfer = alloc_send_cmd28_transfer(dev, 0x02, enroll_init,
fill_send_cmd28_urb(dev, &msg, 0x02, enroll_init, sizeof(enroll_init)); sizeof(enroll_init), enroll_start_sm_cb_init, ssm);
urbh = libusb_async_bulk_transfer(dev->udev, &msg, if (!transfer) {
enroll_start_sm_cb_init, ssm, TIMEOUT); fpi_ssm_mark_aborted(ssm, -ENOMEM);
if (!urbh) { break;
g_free(msg.data); }
fpi_ssm_mark_aborted(ssm, -EIO);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(transfer->buffer);
libusb_free_transfer(transfer);
fpi_ssm_mark_aborted(ssm, r);
} }
break; break;
case READ_ENROLL_MSG28: ; case READ_ENROLL_MSG28: ;
@ -946,7 +987,7 @@ static void enroll_start_sm_run_state(struct fpi_ssm *ssm)
* to subcmd 0 after submitting subcmd 2? */ * to subcmd 0 after submitting subcmd 2? */
/* actually this is probably a poll response? does the above cmd /* actually this is probably a poll response? does the above cmd
* include a 30 01 poll somewhere? */ * include a 30 01 poll somewhere? */
int r = read_msg_async(dev, enroll_start_sm_cb_msg28, ssm); r = read_msg_async(dev, enroll_start_sm_cb_msg28, ssm);
if (r < 0) if (r < 0)
fpi_ssm_mark_aborted(ssm, r); fpi_ssm_mark_aborted(ssm, r);
break; break;
@ -1069,35 +1110,37 @@ static void enroll_iterate_msg_cb(struct fp_dev *dev,
} }
static void enroll_iterate_cmd_cb(libusb_dev_handle *devh, static void enroll_iterate_cmd_cb(struct libusb_transfer *transfer)
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 fp_dev *dev = user_data; struct fp_dev *dev = transfer->user_data;
if (status != FP_URB_COMPLETED) { if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fpi_drvcb_enroll_stage_completed(dev, -EIO, NULL, NULL); fpi_drvcb_enroll_stage_completed(dev, -EIO, NULL, NULL);
} else if (rqlength != actual_length) { } else if (transfer->length != transfer->actual_length) {
fpi_drvcb_enroll_stage_completed(dev, -EPROTO, NULL, NULL); fpi_drvcb_enroll_stage_completed(dev, -EPROTO, NULL, NULL);
} else { } else {
int r = read_msg_async(dev, enroll_iterate_msg_cb, NULL); int r = read_msg_async(dev, enroll_iterate_msg_cb, NULL);
if (r < 0) if (r < 0)
fpi_drvcb_enroll_stage_completed(dev, r, NULL, NULL); fpi_drvcb_enroll_stage_completed(dev, r, NULL, NULL);
} }
libusb_urb_handle_free(urbh); libusb_free_transfer(transfer);
} }
static void enroll_iterate(struct fp_dev *dev) static void enroll_iterate(struct fp_dev *dev)
{ {
struct libusb_bulk_transfer msg; int r;
struct libusb_urb_handle *urbh; struct libusb_transfer *transfer = alloc_send_cmd28_transfer(dev, 0x00,
poll_data, sizeof(poll_data), enroll_iterate_cmd_cb, dev);
fill_send_cmd28_urb(dev, &msg, 0x00, poll_data, sizeof(poll_data)); if (!transfer) {
urbh = libusb_async_bulk_transfer(dev->udev, &msg, enroll_iterate_cmd_cb, fpi_drvcb_enroll_stage_completed(dev, -ENOMEM, NULL, NULL);
dev, TIMEOUT); return;
if (!urbh) { }
g_free(msg.data);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(transfer->buffer);
libusb_free_transfer(transfer);
fpi_drvcb_enroll_stage_completed(dev, -EIO, NULL, NULL); fpi_drvcb_enroll_stage_completed(dev, -EIO, NULL, NULL);
} }
} }
@ -1176,23 +1219,22 @@ static void verify_start_sm_cb_initsm(struct fpi_ssm *initsm)
fpi_ssm_free(initsm); fpi_ssm_free(initsm);
} }
static void verify_init_2803_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void verify_init_2803_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, unsigned char endpoint,
int rqlength, unsigned char *data, int actual_length, void *user_data)
{ {
struct fpi_ssm *ssm = user_data; struct fpi_ssm *ssm = transfer->user_data;
if (status != FP_URB_COMPLETED) if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
fpi_ssm_mark_aborted(ssm, -EIO); fpi_ssm_mark_aborted(ssm, -EIO);
else if (rqlength != actual_length) else if (transfer->length != transfer->actual_length)
fpi_ssm_mark_aborted(ssm, -EPROTO); fpi_ssm_mark_aborted(ssm, -EPROTO);
else else
fpi_ssm_next_state(ssm); fpi_ssm_next_state(ssm);
libusb_urb_handle_free(urbh); libusb_free_transfer(transfer);
} }
static void verify_start_sm_run_state(struct fpi_ssm *ssm) static void verify_start_sm_run_state(struct fpi_ssm *ssm)
{ {
struct fp_dev *dev = ssm->dev; struct fp_dev *dev = ssm->dev;
int r;
switch (ssm->cur_state) { switch (ssm->cur_state) {
case VERIFY_RUN_INITSM: ; case VERIFY_RUN_INITSM: ;
@ -1204,18 +1246,22 @@ static void verify_start_sm_run_state(struct fpi_ssm *ssm)
struct fp_print_data *print = dev->verify_data; struct fp_print_data *print = dev->verify_data;
size_t data_len = sizeof(verify_hdr) + print->length; size_t data_len = sizeof(verify_hdr) + print->length;
unsigned char *data = g_malloc(data_len); unsigned char *data = g_malloc(data_len);
struct libusb_bulk_transfer msg; struct libusb_transfer *transfer;
struct libusb_urb_handle *urbh;
memcpy(data, verify_hdr, sizeof(verify_hdr)); memcpy(data, verify_hdr, sizeof(verify_hdr));
memcpy(data + sizeof(verify_hdr), print->data, print->length); memcpy(data + sizeof(verify_hdr), print->data, print->length);
fill_send_cmd28_urb(dev, &msg, 0x03, data, data_len); transfer = alloc_send_cmd28_transfer(dev, 0x03, data, data_len,
verify_init_2803_cb, ssm);
g_free(data); g_free(data);
if (!transfer) {
fpi_ssm_mark_aborted(ssm, -ENOMEM);
break;
}
urbh = libusb_async_bulk_transfer(dev->udev, &msg, r = libusb_submit_transfer(transfer);
verify_init_2803_cb, ssm, TIMEOUT); if (r < 0) {
if (!urbh) { g_free(transfer->buffer);
g_free(msg.data); libusb_free_transfer(transfer);
fpi_ssm_mark_aborted(ssm, -EIO); fpi_ssm_mark_aborted(ssm, -EIO);
} }
break; break;
@ -1323,28 +1369,25 @@ static void verify_rd2800_cb(struct fp_dev *dev, enum read_msg_status msgstat,
fpi_drvcb_report_verify_result(dev, -EPROTO, NULL); fpi_drvcb_report_verify_result(dev, -EPROTO, NULL);
} }
static void verify_wr2800_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void verify_wr2800_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, unsigned char endpoint,
int rqlength, unsigned char *data, int actual_length, void *user_data)
{ {
struct fp_dev *dev = user_data; struct fp_dev *dev = transfer->user_data;
if (status != FP_URB_COMPLETED) { if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fpi_drvcb_report_verify_result(dev, -EIO, NULL); fpi_drvcb_report_verify_result(dev, -EIO, NULL);
} else if (rqlength != actual_length) { } else if (transfer->length != transfer->actual_length) {
fpi_drvcb_report_verify_result(dev, -EIO, NULL); fpi_drvcb_report_verify_result(dev, -EIO, NULL);
} else { } else {
int r = read_msg_async(dev, verify_rd2800_cb, NULL); int r = read_msg_async(dev, verify_rd2800_cb, NULL);
if (r < 0) if (r < 0)
fpi_drvcb_report_verify_result(dev, r, NULL); fpi_drvcb_report_verify_result(dev, r, NULL);
} }
libusb_urb_handle_free(urbh); libusb_free_transfer(transfer);
} }
static void verify_iterate(struct fp_dev *dev) static void verify_iterate(struct fp_dev *dev)
{ {
struct upekts_dev *upekdev = dev->priv; struct upekts_dev *upekdev = dev->priv;
struct libusb_bulk_transfer msg;
if (upekdev->stop_verify) { if (upekdev->stop_verify) {
do_verify_stop(dev); do_verify_stop(dev);
@ -1359,12 +1402,19 @@ static void verify_iterate(struct fp_dev *dev)
if (r < 0) if (r < 0)
fpi_drvcb_report_verify_result(dev, r, NULL); fpi_drvcb_report_verify_result(dev, r, NULL);
} else { } else {
struct libusb_urb_handle *urbh; int r;
fill_send_cmd28_urb(dev, &msg, 0x00, poll_data, sizeof(poll_data)); struct libusb_transfer *transfer = alloc_send_cmd28_transfer(dev,
urbh = libusb_async_bulk_transfer(dev->udev, &msg, verify_wr2800_cb, 0x00, poll_data, sizeof(poll_data), verify_wr2800_cb, dev);
dev, TIMEOUT);
if (!urbh) { if (!transfer) {
g_free(msg.data); fpi_drvcb_report_verify_result(dev, -ENOMEM, NULL);
return;
}
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(transfer->buffer);
libusb_free_transfer(transfer);
fpi_drvcb_report_verify_result(dev, -EIO, NULL); fpi_drvcb_report_verify_result(dev, -EIO, NULL);
} }
} }

View file

@ -122,8 +122,8 @@ struct uru4k_dev {
enum fp_imgdev_state activate_state; enum fp_imgdev_state activate_state;
unsigned char last_hwstat_rd; unsigned char last_hwstat_rd;
libusb_urb_handle *irq_transfer; struct libusb_transfer *irq_transfer;
libusb_urb_handle *img_transfer; struct libusb_transfer *img_transfer;
irq_cb_fn irq_cb; irq_cb_fn irq_cb;
void *irq_cb_data; void *irq_cb_data;
@ -154,19 +154,18 @@ struct set_reg_data {
void *user_data; void *user_data;
}; };
static void set_reg_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void set_reg_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, struct libusb_ctrl_setup *setup,
unsigned char *data, int actual_length, void *user_data)
{ {
struct set_reg_data *srdata = user_data; struct set_reg_data *srdata = transfer->user_data;
int r = 0; int r = 0;
if (status != FP_URB_COMPLETED) if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
r = -EIO; r = -EIO;
else if (setup->wLength != actual_length) else if (transfer->actual_length != 1)
r = -EPROTO; r = -EPROTO;
libusb_urb_handle_free(urbh); g_free(transfer->buffer);
libusb_free_transfer(transfer);
srdata->callback(srdata->dev, r, srdata->user_data); srdata->callback(srdata->dev, r, srdata->user_data);
g_free(srdata); g_free(srdata);
} }
@ -174,29 +173,32 @@ static void set_reg_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh,
static int set_reg(struct fp_img_dev *dev, unsigned char reg, static int set_reg(struct fp_img_dev *dev, unsigned char reg,
unsigned char value, set_reg_cb_fn callback, void *user_data) unsigned char value, set_reg_cb_fn callback, void *user_data)
{ {
struct set_reg_data *srdata = g_malloc(sizeof(*srdata)); struct set_reg_data *srdata;
struct libusb_urb_handle *urbh; struct libusb_transfer *transfer = libusb_alloc_transfer();
struct libusb_control_transfer trf = { unsigned char *data;
.requesttype = CTRL_OUT, int r;
.request = USB_RQ,
.value = reg,
.index = 0,
.length = 1,
.data = &value,
};
if (!transfer)
return -ENOMEM;
srdata = g_malloc(sizeof(*srdata));
srdata->dev = dev; srdata->dev = dev;
srdata->callback = callback; srdata->callback = callback;
srdata->user_data = user_data; srdata->user_data = user_data;
trf.data[0] = value; data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
urbh = libusb_async_control_transfer(dev->udev, &trf, set_reg_cb, srdata, data[LIBUSB_CONTROL_SETUP_SIZE] = value;
CTRL_TIMEOUT); libusb_fill_control_setup(data, CTRL_OUT, USB_RQ, reg, 0, 1);
if (!urbh) { libusb_fill_control_transfer(transfer, dev->udev, data, set_reg_cb,
srdata, CTRL_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(srdata); g_free(srdata);
return -EIO; g_free(data);
libusb_free_transfer(transfer);
} }
return 0; return r;
} }
/* /*
@ -233,59 +235,65 @@ struct c_r_data {
void *user_data; void *user_data;
}; };
static void response_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void response_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, struct libusb_ctrl_setup *setup,
unsigned char *data, int actual_length, void *user_data)
{ {
struct c_r_data *crdata = user_data; struct c_r_data *crdata = transfer->user_data;
int r = 0; int r = 0;
if (status == FP_URB_COMPLETED) if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
r = -EIO; r = -EIO;
else if (actual_length != setup->wLength) else if (transfer->actual_length != CR_LENGTH)
r = -EPROTO; r = -EPROTO;
libusb_urb_handle_free(urbh); g_free(transfer->buffer);
libusb_free_transfer(transfer);
crdata->callback(crdata->dev, r, crdata->user_data); crdata->callback(crdata->dev, r, crdata->user_data);
} }
static void challenge_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void challenge_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, struct libusb_ctrl_setup *setup,
unsigned char *data, int actual_length, void *user_data)
{ {
struct c_r_data *crdata = user_data; struct c_r_data *crdata = transfer->user_data;
struct fp_img_dev *dev = crdata->dev; struct fp_img_dev *dev = crdata->dev;
struct uru4k_dev *urudev = dev->priv; struct uru4k_dev *urudev = dev->priv;
unsigned char respdata[CR_LENGTH]; struct libusb_transfer *resp_transfer;
unsigned char *respdata;
int r;
struct libusb_urb_handle *resp_urbh; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
struct libusb_control_transfer trf_write_response = {
.requesttype = CTRL_OUT,
.request = USB_RQ,
.value = REG_RESPONSE,
.index = 0,
.data = respdata,
.length = sizeof(respdata),
};
if (status != FP_URB_COMPLETED) {
crdata->callback(crdata->dev, -EIO, crdata->user_data); crdata->callback(crdata->dev, -EIO, crdata->user_data);
goto out; goto out;
} else if (setup->wLength != actual_length) { } else if (transfer->actual_length != CR_LENGTH) {
crdata->callback(crdata->dev, -EPROTO, crdata->user_data); crdata->callback(crdata->dev, -EPROTO, crdata->user_data);
goto out; goto out;
} }
/* produce response from challenge */
AES_encrypt(data, respdata, &urudev->aeskey);
/* submit response */ /* submit response */
resp_urbh = libusb_async_control_transfer(dev->udev, &trf_write_response, resp_transfer = libusb_alloc_transfer();
response_cb, crdata, CTRL_TIMEOUT); if (!resp_transfer) {
if (!resp_urbh) crdata->callback(crdata->dev, -ENOMEM, crdata->user_data);
crdata->callback(crdata->dev, -EIO, crdata->user_data); goto out;
}
respdata = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + CR_LENGTH);
libusb_fill_control_setup(respdata, CTRL_OUT, USB_RQ, REG_RESPONSE, 0,
CR_LENGTH);
libusb_fill_control_transfer(transfer, dev->udev, respdata, response_cb,
crdata, CTRL_TIMEOUT);
/* produce response from challenge */
AES_encrypt(libusb_control_transfer_get_data(transfer),
respdata + LIBUSB_CONTROL_SETUP_SIZE, &urudev->aeskey);
r = libusb_submit_transfer(resp_transfer);
if (r < 0) {
g_free(respdata);
libusb_free_transfer(resp_transfer);
crdata->callback(crdata->dev, r, crdata->user_data);
}
out: out:
libusb_urb_handle_free(urbh); g_free(transfer->buffer);
libusb_free_transfer(transfer);
} }
/* /*
@ -296,28 +304,33 @@ out:
static int do_challenge_response(struct fp_img_dev *dev, static int do_challenge_response(struct fp_img_dev *dev,
challenge_response_cb callback, void *user_data) challenge_response_cb callback, void *user_data)
{ {
struct c_r_data *crdata = g_malloc(sizeof(*crdata)); struct libusb_transfer *transfer = libusb_alloc_transfer();;
struct libusb_urb_handle *urbh; struct c_r_data *crdata;
struct libusb_control_transfer trf_read_challenge = { unsigned char *data;
.requesttype = CTRL_IN, int r;
.request = USB_RQ,
.value = REG_CHALLENGE,
.index = 0,
.length = CR_LENGTH,
};
fp_dbg(""); fp_dbg("");
if (!transfer)
return -ENOMEM;
crdata = g_malloc(sizeof(*crdata));
crdata->dev = dev; crdata->dev = dev;
crdata->callback = callback; crdata->callback = callback;
crdata->user_data = user_data; crdata->user_data = user_data;
urbh = libusb_async_control_transfer(dev->udev, &trf_read_challenge, data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + CR_LENGTH);
challenge_cb, crdata, CTRL_TIMEOUT); libusb_fill_control_setup(data, CTRL_IN, USB_RQ, REG_CHALLENGE, 0,
if (!urbh) { CR_LENGTH);
libusb_fill_control_transfer(transfer, dev->udev, data, challenge_cb,
crdata, CTRL_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(crdata); g_free(crdata);
return -EIO; g_free(data);
libusb_free_transfer(transfer);
} }
return 0; return r;
} }
/***** INTERRUPT HANDLING *****/ /***** INTERRUPT HANDLING *****/
@ -326,35 +339,33 @@ static int do_challenge_response(struct fp_img_dev *dev,
static int start_irq_handler(struct fp_img_dev *dev); static int start_irq_handler(struct fp_img_dev *dev);
static void irq_handler(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void irq_handler(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, unsigned char endpoint,
int rqlength, unsigned char *data, int actual_length, void *user_data)
{ {
struct fp_img_dev *dev = user_data; struct fp_img_dev *dev = transfer->user_data;
struct uru4k_dev *urudev = dev->priv; struct uru4k_dev *urudev = dev->priv;
unsigned char *data = transfer->buffer;
uint16_t type; uint16_t type;
int r = 0; int r = 0;
libusb_urb_handle_free(urbh); if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
if (status == FP_URB_CANCELLED) {
fp_dbg("cancelled"); fp_dbg("cancelled");
if (urudev->irqs_stopped_cb) if (urudev->irqs_stopped_cb)
urudev->irqs_stopped_cb(dev); urudev->irqs_stopped_cb(dev);
urudev->irqs_stopped_cb = NULL; urudev->irqs_stopped_cb = NULL;
goto out; goto out;
} else if (status != FP_URB_COMPLETED) { } else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
r = -EIO; r = -EIO;
goto err; goto err;
} else if (actual_length != rqlength) { } else if (transfer->actual_length != transfer->length) {
fp_err("short interrupt read? %d", actual_length); fp_err("short interrupt read? %d", transfer->actual_length);
r = -EPROTO; r = -EPROTO;
goto err; goto err;
} }
type = GUINT16_FROM_BE(*((uint16_t *) data)); type = GUINT16_FROM_BE(*((uint16_t *) data));
g_free(data);
fp_dbg("recv irq type %04x", type); fp_dbg("recv irq type %04x", type);
g_free(data);
libusb_free_transfer(transfer);
/* The 0800 interrupt seems to indicate imminent failure (0 bytes transfer) /* The 0800 interrupt seems to indicate imminent failure (0 bytes transfer)
* of the next scan. It still appears on occasion. */ * of the next scan. It still appears on occasion. */
@ -370,41 +381,47 @@ static void irq_handler(libusb_dev_handle *devh, libusb_urb_handle *urbh,
if (r == 0) if (r == 0)
return; return;
transfer = NULL;
data = NULL; data = NULL;
err: err:
if (urudev->irq_cb) if (urudev->irq_cb)
urudev->irq_cb(dev, r, 0, urudev->irq_cb_data); urudev->irq_cb(dev, r, 0, urudev->irq_cb_data);
out: out:
g_free(data); g_free(data);
libusb_free_transfer(transfer);
urudev->irq_transfer = NULL; urudev->irq_transfer = NULL;
} }
static int start_irq_handler(struct fp_img_dev *dev) static int start_irq_handler(struct fp_img_dev *dev)
{ {
struct uru4k_dev *urudev = dev->priv; struct uru4k_dev *urudev = dev->priv;
struct libusb_urb_handle *urbh; struct libusb_transfer *transfer = libusb_alloc_transfer();
struct libusb_bulk_transfer trf = { unsigned char *data;
.endpoint = EP_INTR, int r;
.length = IRQ_LENGTH,
.data = g_malloc(IRQ_LENGTH),
};
urbh = libusb_async_interrupt_transfer(dev->udev, &trf, irq_handler, dev, if (!transfer)
0); return -ENOMEM;
urudev->irq_transfer = urbh;
if (!urbh) { data = g_malloc(IRQ_LENGTH);
g_free(trf.data); libusb_fill_bulk_transfer(transfer, dev->udev, EP_INTR, data, IRQ_LENGTH,
return -EIO; irq_handler, dev, 0);
urudev->irq_transfer = transfer;
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
urudev->irq_transfer = NULL;
} }
return 0; return r;
} }
static void stop_irq_handler(struct fp_img_dev *dev, irqs_stopped_cb_fn cb) static void stop_irq_handler(struct fp_img_dev *dev, irqs_stopped_cb_fn cb)
{ {
struct uru4k_dev *urudev = dev->priv; struct uru4k_dev *urudev = dev->priv;
struct libusb_urb_handle *urbh = urudev->irq_transfer; struct libusb_transfer *transfer = urudev->irq_transfer;
if (urbh) { if (transfer) {
libusb_urb_handle_cancel(dev->udev, urbh); libusb_cancel_transfer(transfer);
urudev->irqs_stopped_cb = cb; urudev->irqs_stopped_cb = cb;
} }
} }
@ -413,46 +430,45 @@ static void stop_irq_handler(struct fp_img_dev *dev, irqs_stopped_cb_fn cb)
static int start_imaging_loop(struct fp_img_dev *dev); static int start_imaging_loop(struct fp_img_dev *dev);
static void image_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void image_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, unsigned char endpoint,
int rqlength, unsigned char *data, int actual_length, void *user_data)
{ {
struct fp_img_dev *dev = user_data; struct fp_img_dev *dev = transfer->user_data;
struct uru4k_dev *urudev = dev->priv; struct uru4k_dev *urudev = dev->priv;
int hdr_skip = CAPTURE_HDRLEN; int hdr_skip = CAPTURE_HDRLEN;
int image_size = DATABLK_EXPECT - CAPTURE_HDRLEN; int image_size = DATABLK_EXPECT - CAPTURE_HDRLEN;
struct fp_img *img; struct fp_img *img;
int r = 0; int r = 0;
libusb_urb_handle_free(urbh); if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
if (status == FP_URB_CANCELLED) {
fp_dbg("cancelled"); fp_dbg("cancelled");
urudev->img_transfer = NULL; urudev->img_transfer = NULL;
g_free(data); g_free(transfer->buffer);
libusb_free_transfer(transfer);
return; return;
} else if (status != FP_URB_COMPLETED) { } else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
r = -EIO; r = -EIO;
goto out; goto out;
} }
if (actual_length == image_size) { if (transfer->actual_length == image_size) {
/* no header! this is rather odd, but it happens sometimes with my MS /* no header! this is rather odd, but it happens sometimes with my MS
* keyboard */ * keyboard */
fp_dbg("got image with no header!"); fp_dbg("got image with no header!");
hdr_skip = 0; hdr_skip = 0;
} else if (actual_length != DATABLK_EXPECT) { } else if (transfer->actual_length != DATABLK_EXPECT) {
fp_err("unexpected image capture size (%d)", actual_length); fp_err("unexpected image capture size (%d)", transfer->actual_length);
r = -EPROTO; r = -EPROTO;
goto out; goto out;
} }
img = fpi_img_new(image_size); img = fpi_img_new(image_size);
memcpy(img->data, data + hdr_skip, image_size); memcpy(img->data, transfer->buffer + hdr_skip, image_size);
img->flags = FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED | FP_IMG_COLORS_INVERTED; img->flags = FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED | FP_IMG_COLORS_INVERTED;
fpi_imgdev_image_captured(dev, img); fpi_imgdev_image_captured(dev, img);
out: out:
g_free(data); g_free(transfer->buffer);
libusb_free_transfer(transfer);
if (r == 0) if (r == 0)
r = start_imaging_loop(dev); r = start_imaging_loop(dev);
@ -463,29 +479,33 @@ out:
static int start_imaging_loop(struct fp_img_dev *dev) static int start_imaging_loop(struct fp_img_dev *dev)
{ {
struct uru4k_dev *urudev = dev->priv; struct uru4k_dev *urudev = dev->priv;
struct libusb_urb_handle *urbh; struct libusb_transfer *transfer = libusb_alloc_transfer();
struct libusb_bulk_transfer trf = { unsigned char *data;
.endpoint = EP_DATA, int r;
.length = DATABLK_RQLEN,
.data = g_malloc(DATABLK_RQLEN),
};
urbh = libusb_async_bulk_transfer(dev->udev, &trf, image_cb, dev, 0); if (!transfer)
urudev->img_transfer = urbh; return -ENOMEM;
if (!urbh) {
g_free(trf.data); data = g_malloc(DATABLK_RQLEN);
return -EIO; libusb_fill_bulk_transfer(transfer, dev->udev, EP_DATA, data,
DATABLK_RQLEN, image_cb, dev, 0);
urudev->img_transfer = transfer;
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
} }
return 0; return r;
} }
static void stop_imaging_loop(struct fp_img_dev *dev) static void stop_imaging_loop(struct fp_img_dev *dev)
{ {
struct uru4k_dev *urudev = dev->priv; struct uru4k_dev *urudev = dev->priv;
libusb_urb_handle *urbh = urudev->img_transfer; struct libusb_transfer *transfer = urudev->img_transfer;
if (urbh) if (transfer)
libusb_urb_handle_cancel(dev->udev, urbh); libusb_cancel_transfer(transfer);
/* FIXME: should probably wait for cancellation to complete */ /* FIXME: should probably wait for cancellation to complete */
} }
@ -577,68 +597,72 @@ static void sm_set_hwstat(struct fpi_ssm *ssm, unsigned char value)
sm_set_reg(ssm, REG_HWSTAT, value); sm_set_reg(ssm, REG_HWSTAT, value);
} }
static void sm_get_hwstat_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void sm_get_hwstat_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, struct libusb_ctrl_setup *setup,
unsigned char *data, int actual_length, void *user_data)
{ {
struct fpi_ssm *ssm = user_data; struct fpi_ssm *ssm = transfer->user_data;
struct fp_img_dev *dev = ssm->priv; struct fp_img_dev *dev = ssm->priv;
struct uru4k_dev *urudev = dev->priv; struct uru4k_dev *urudev = dev->priv;
if (status != FP_URB_COMPLETED) { if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fpi_ssm_mark_aborted(ssm, -EIO); fpi_ssm_mark_aborted(ssm, -EIO);
} else if (setup->wLength != actual_length) { } else if (transfer->actual_length != 1) {
fpi_ssm_mark_aborted(ssm, -EPROTO); fpi_ssm_mark_aborted(ssm, -EPROTO);
} else { } else {
urudev->last_hwstat_rd = *data; urudev->last_hwstat_rd = libusb_control_transfer_get_data(transfer)[0];
fp_dbg("value %02x", urudev->last_hwstat_rd); fp_dbg("value %02x", urudev->last_hwstat_rd);
fpi_ssm_next_state(ssm); fpi_ssm_next_state(ssm);
} }
libusb_urb_handle_free(urbh); g_free(transfer->buffer);
libusb_free_transfer(transfer);
} }
static void sm_get_hwstat(struct fpi_ssm *ssm) static void sm_get_hwstat(struct fpi_ssm *ssm)
{ {
struct fp_img_dev *dev = ssm->priv; struct fp_img_dev *dev = ssm->priv;
struct libusb_urb_handle *urbh; struct libusb_transfer *transfer = libusb_alloc_transfer();
unsigned char *data;
int r;
if (!transfer) {
fpi_ssm_mark_aborted(ssm, -ENOMEM);
return;
}
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
/* The windows driver uses a request of 0x0c here. We use 0x04 to be /* The windows driver uses a request of 0x0c here. We use 0x04 to be
* consistent with every other command we know about. */ * consistent with every other command we know about. */
/* FIXME is the above comment still true? */ /* FIXME is the above comment still true? */
struct libusb_control_transfer trf = { libusb_fill_control_setup(data, CTRL_IN, USB_RQ, REG_HWSTAT, 0, 1);
.requesttype = CTRL_IN, libusb_fill_control_transfer(transfer, dev->udev, data, sm_get_hwstat_cb,
.request = USB_RQ,
.value = REG_HWSTAT,
.index = 0,
.length = 1,
};
urbh = libusb_async_control_transfer(dev->udev, &trf, sm_get_hwstat_cb,
ssm, CTRL_TIMEOUT); ssm, CTRL_TIMEOUT);
if (!urbh)
r = libusb_submit_transfer(transfer);
if (r < 0) {
g_free(data);
libusb_free_transfer(transfer);
fpi_ssm_mark_aborted(ssm, -EIO); fpi_ssm_mark_aborted(ssm, -EIO);
}
} }
static void sm_fix_fw_read_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh, static void sm_fix_fw_read_cb(struct libusb_transfer *transfer)
enum libusb_urb_cb_status status, struct libusb_ctrl_setup *setup,
unsigned char *data, int actual_length, void *user_data)
{ {
struct fpi_ssm *ssm = user_data; struct fpi_ssm *ssm = transfer->user_data;
struct fp_img_dev *dev = ssm->priv; struct fp_img_dev *dev = ssm->priv;
struct uru4k_dev *urudev = dev->priv; struct uru4k_dev *urudev = dev->priv;
unsigned char new; unsigned char new;
unsigned char fwenc; unsigned char fwenc;
uint32_t enc_addr = FIRMWARE_START + urudev->profile->fw_enc_offset; uint32_t enc_addr = FIRMWARE_START + urudev->profile->fw_enc_offset;
if (status != FP_URB_COMPLETED) { if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fpi_ssm_mark_aborted(ssm, -EIO); fpi_ssm_mark_aborted(ssm, -EIO);
goto out; goto out;
} else if (actual_length != setup->wLength) { } else if (transfer->actual_length != 1) {
fpi_ssm_mark_aborted(ssm, -EPROTO); fpi_ssm_mark_aborted(ssm, -EPROTO);
goto out; goto out;
} }
fwenc = data[0]; fwenc = libusb_control_transfer_get_data(transfer)[0];
fp_dbg("firmware encryption byte at %x reads %02x", enc_addr, fwenc); fp_dbg("firmware encryption byte at %x reads %02x", enc_addr, fwenc);
if (fwenc != 0x07 && fwenc != 0x17) if (fwenc != 0x07 && fwenc != 0x17)
fp_dbg("strange encryption byte value, please report this"); fp_dbg("strange encryption byte value, please report this");
@ -652,7 +676,8 @@ static void sm_fix_fw_read_cb(libusb_dev_handle *devh, libusb_urb_handle *urbh,
} }
out: out:
libusb_urb_handle_free(urbh); g_free(transfer->buffer);
libusb_free_transfer(transfer);
} }
static void sm_fix_firmware(struct fpi_ssm *ssm) static void sm_fix_firmware(struct fpi_ssm *ssm)
@ -660,20 +685,26 @@ static void sm_fix_firmware(struct fpi_ssm *ssm)
struct fp_img_dev *dev = ssm->priv; struct fp_img_dev *dev = ssm->priv;
struct uru4k_dev *urudev = dev->priv; struct uru4k_dev *urudev = dev->priv;
uint32_t enc_addr = FIRMWARE_START + urudev->profile->fw_enc_offset; uint32_t enc_addr = FIRMWARE_START + urudev->profile->fw_enc_offset;
struct libusb_transfer *transfer = libusb_alloc_transfer();
unsigned char *data;
int r;
struct libusb_urb_handle *urbh; if (!transfer) {
struct libusb_control_transfer trf_read_fw = { fpi_ssm_mark_aborted(ssm, -ENOMEM);
.requesttype = 0xc0, return;
.request = 0x0c, }
.value = enc_addr,
.index = 0, data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
.length = 1, libusb_fill_control_setup(data, 0xc0, 0x0c, enc_addr, 0, 1);
}; libusb_fill_control_transfer(transfer, dev->udev, data, sm_fix_fw_read_cb,
ssm, CTRL_TIMEOUT);
urbh = libusb_async_control_transfer(dev->udev, &trf_read_fw, r = libusb_submit_transfer(transfer);
sm_fix_fw_read_cb, ssm, CTRL_TIMEOUT); if (r < 0) {
if (!urbh) g_free(data);
fpi_ssm_mark_aborted(ssm, -EIO); libusb_free_transfer(transfer);
fpi_ssm_mark_aborted(ssm, r);
}
} }
/***** INITIALIZATION *****/ /***** INITIALIZATION *****/
@ -1070,7 +1101,7 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
int r; int r;
/* Find fingerprint interface */ /* Find fingerprint interface */
config = libusb_dev_get_config(libusb_devh_get_dev(dev->udev)); config = libusb_get_config_descriptor(libusb_get_device(dev->udev));
for (i = 0; i < config->bNumInterfaces; i++) { for (i = 0; i < config->bNumInterfaces; i++) {
struct libusb_interface *cur_iface = &config->interface[i]; struct libusb_interface *cur_iface = &config->interface[i];

View file

@ -93,7 +93,7 @@ enum fp_dev_state {
struct fp_dev { struct fp_dev {
struct fp_driver *drv; struct fp_driver *drv;
libusb_dev_handle *udev; libusb_device_handle *udev;
uint32_t devtype; uint32_t devtype;
void *priv; void *priv;
@ -161,7 +161,7 @@ enum fp_imgdev_verify_state {
struct fp_img_dev { struct fp_img_dev {
struct fp_dev *dev; struct fp_dev *dev;
libusb_dev_handle *udev; libusb_device_handle *udev;
enum fp_imgdev_action action; enum fp_imgdev_action action;
int action_state; int action_state;
@ -249,7 +249,7 @@ void fpi_img_driver_setup(struct fp_img_driver *idriver);
container_of((drv), struct fp_img_driver, driver) container_of((drv), struct fp_img_driver, driver)
struct fp_dscv_dev { struct fp_dscv_dev {
libusb_dev *udev; struct libusb_device *udev;
struct fp_driver *drv; struct fp_driver *drv;
unsigned long driver_data; unsigned long driver_data;
uint32_t devtype; uint32_t devtype;

View file

@ -180,7 +180,7 @@ API_EXPORTED int fp_enroll_finger_img(struct fp_dev *dev,
int stage = dev->__enroll_stage; int stage = dev->__enroll_stage;
gboolean final = FALSE; gboolean final = FALSE;
gboolean stopped = FALSE; gboolean stopped = FALSE;
struct sync_enroll_data *edata; struct sync_enroll_data *edata = NULL;
int r; int r;
fp_dbg(""); fp_dbg("");