diff --git a/doc/libfprint-sections.txt b/doc/libfprint-sections.txt
index 6b02bcde..0a95c2d5 100644
--- a/doc/libfprint-sections.txt
+++ b/doc/libfprint-sections.txt
@@ -197,5 +197,11 @@ FP_INSTANCE_DATA
fpi-usb.h
fpi-usb
+fpi_usb_transfer
+
+fpi_usb_transfer_cb_fn
fpi_usb_alloc
+fpi_usb_fill_bulk_transfer
+fpi_usb_submit_transfer
+fpi_usb_cancel_transfer
diff --git a/libfprint/fpi-usb.c b/libfprint/fpi-usb.c
index 1b8a92e7..8b06ebb4 100644
--- a/libfprint/fpi-usb.c
+++ b/libfprint/fpi-usb.c
@@ -18,6 +18,7 @@
*/
#include "fpi-usb.h"
+#include "drivers_api.h"
/**
* SECTION:fpi-usb
@@ -57,6 +58,14 @@ mem_error (const char *format,
_exit (1);
}
+struct fpi_usb_transfer {
+ struct libusb_transfer *transfer;
+ fpi_ssm *ssm;
+ struct fp_dev *dev;
+ fpi_usb_transfer_cb_fn callback;
+ void *user_data;
+};
+
/**
* fpi_usb_alloc:
*
@@ -75,3 +84,152 @@ fpi_usb_alloc(void)
return transfer;
}
+
+static fpi_usb_transfer *
+fpi_usb_transfer_new(struct fp_dev *dev,
+ fpi_ssm *ssm,
+ fpi_usb_transfer_cb_fn callback,
+ void *user_data)
+{
+ fpi_usb_transfer *transfer;
+
+ transfer = g_new0(fpi_usb_transfer, 1);
+ transfer->transfer = fpi_usb_alloc();
+ transfer->dev = dev;
+ transfer->ssm = ssm;
+ transfer->callback = callback;
+ transfer->user_data = user_data;
+
+ return transfer;
+}
+
+void
+fpi_usb_transfer_free(fpi_usb_transfer *transfer)
+{
+ if (transfer == NULL)
+ return;
+
+ g_free(transfer->transfer->buffer);
+ libusb_free_transfer(transfer->transfer);
+ g_free(transfer);
+}
+
+static void
+fpi_usb_transfer_cb (struct libusb_transfer *transfer)
+{
+ fpi_usb_transfer *t;
+
+ g_assert(transfer);
+ g_assert(transfer->user_data);
+
+ t = transfer->user_data;
+ BUG_ON(transfer->callback == NULL);
+ (t->callback) (transfer, t->dev, t->ssm, t->user_data);
+ fpi_usb_transfer_free(t);
+}
+
+/**
+ * fpi_usb_fill_bulk_transfer:
+ * @dev: a struct #fp_dev fingerprint device
+ * @ssm: the current #fpi_ssm state machine
+ * @endpoint: the USB end point
+ * @buffer: a buffer allocated with g_malloc() or another GLib function.
+ * Note that the returned #fpi_usb_transfer will own this buffer, so it
+ * should not be freed manually.
+ * @length: the size of @buffer
+ * @callback: the callback function that will be called once the fpi_usb_submit_transfer()
+ * call finishes.
+ * @user_data: a user data pointer to pass to the callback
+ * @timeout: timeout for the transfer in milliseconds, or 0 for no timeout
+ *
+ * This function is similar to calling [`libusb_alloc_transfer(0)`](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga13cc69ea40c702181c430c950121c000)]
+ * followed by calling [`libusb_fill_bulk_transfer()`](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gad4ddb1a5c6c7fefc979a44d7300b95d7).
+ * The #fpi_usb_transfer_cb_fn callback will however provide more arguments
+ * relevant to libfprint drivers, making it a good replacement for the raw libusb
+ * calls.
+ *
+ * Returns: a #fpi_usb_transfer transfer struct, to be passed to
+ * fpi_usb_submit_transfer().
+ */
+fpi_usb_transfer *
+fpi_usb_fill_bulk_transfer (struct fp_dev *dev,
+ fpi_ssm *ssm,
+ unsigned char endpoint,
+ unsigned char *buffer,
+ int length,
+ fpi_usb_transfer_cb_fn callback,
+ void *user_data,
+ unsigned int timeout)
+{
+ fpi_usb_transfer *transfer;
+
+ g_return_val_if_fail (dev != NULL, NULL);
+ g_return_val_if_fail (callback != NULL, NULL);
+
+ transfer = fpi_usb_transfer_new(dev,
+ ssm,
+ callback,
+ user_data);
+
+ libusb_fill_bulk_transfer(transfer->transfer,
+ fpi_dev_get_usb_dev(dev),
+ endpoint,
+ buffer,
+ length,
+ fpi_usb_transfer_cb,
+ transfer,
+ timeout);
+
+ return transfer;
+}
+
+/**
+ * fpi_usb_submit_transfer:
+ * @transfer: a #fpi_usb_transfer struct
+ *
+ * Start a transfer to the device with the provided #fpi_usb_transfer.
+ * On error, the #fpi_usb_transfer struct will be freed, otherwise it will
+ * be freed once the callback provided to fpi_usb_fill_bulk_transfer() has
+ * been called.
+ *
+ * Returns: 0 on success, or the same errors as [libusb_submit_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gabb0932601f2c7dad2fee4b27962848ce)
+ * on failure.
+ */
+int
+fpi_usb_submit_transfer(fpi_usb_transfer *transfer)
+{
+ int r;
+
+ g_return_val_if_fail (transfer != NULL, LIBUSB_ERROR_INVALID_PARAM);
+
+ r = libusb_submit_transfer(transfer->transfer);
+ if (r < 0)
+ fpi_usb_transfer_free(transfer);
+
+ return r;
+}
+
+/**
+ * fpi_usb_cancel_transfer:
+ * @transfer: a #fpi_usb_transfer struct
+ *
+ * Cancel a transfer to the device with the provided #fpi_usb_transfer.
+ * Note that this will not complete the cancellation, as your transfer
+ * callback will be called with the `LIBUSB_TRANSFER_CANCELLED` status,
+ * as [libusb_cancel_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga685eb7731f9a0593f75beb99727bbe54)
+ * would.
+ *
+ * You should not access anything but the given struct #libusb_transfer
+ * in the callback before checking whether `LIBUSB_TRANSFER_CANCELLED` has
+ * been called, as that might cause memory access violations.
+ *
+ * Returns: 0 on success, or the same errors as [libusb_cancel_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga685eb7731f9a0593f75beb99727bbe54)
+ * on failure.
+ */
+int
+fpi_usb_cancel_transfer(fpi_usb_transfer *transfer)
+{
+ g_return_val_if_fail (transfer != NULL, LIBUSB_ERROR_NOT_FOUND);
+
+ return libusb_cancel_transfer(transfer->transfer);
+}
diff --git a/libfprint/fpi-usb.h b/libfprint/fpi-usb.h
index c966678e..625a7e7b 100644
--- a/libfprint/fpi-usb.h
+++ b/libfprint/fpi-usb.h
@@ -21,7 +21,51 @@
#define __FPI_USB_H__
#include
+#include "fpi-dev.h"
+#include "fpi-ssm.h"
+
+/**
+ * fpi_usb_transfer:
+ *
+ * A structure containing the arguments passed to fpi_usb_fill_bulk_transfer()
+ * to be used with fpi_usb_submit_transfer().
+ */
+typedef struct fpi_usb_transfer fpi_usb_transfer;
+
+/**
+ * fpi_usb_transfer_cb_fn:
+ * @transfer: a struct #libusb_transfer
+ * @dev: the struct #fp_dev on which the operation was performed
+ * @ssm: the #fpi_ssm state machine
+ * @user_data: the user data passed to fpi_usb_fill_bulk_transfer()
+ *
+ * This callback will be called in response to a libusb bulk transfer
+ * triggered via fpi_usb_fill_bulk_transfer() finishing. Note that the
+ * struct #libusb_transfer does not need to be freed, as it will be
+ * freed after the callback returns, similarly to
+ * the [LIBUSB_TRANSFER_FREE_TRANSFER flag](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gga1fb47dd0f7c209b60a3609ff0c03d56dacf3f064997b283a14097c9f4d6f8ccc1).
+ *
+ * Note that the cancelled status of the transfer should be checked
+ * first thing, as the @dev, @ssm and @user_data pointers might not
+ * be pointing to valid values anymore. See fpi_usb_cancel_transfer()
+ * for more information.
+ */
+typedef void(*fpi_usb_transfer_cb_fn) (struct libusb_transfer *transfer,
+ struct fp_dev *dev,
+ fpi_ssm *ssm,
+ void *user_data);
struct libusb_transfer *fpi_usb_alloc(void) __attribute__((returns_nonnull));
+fpi_usb_transfer *fpi_usb_fill_bulk_transfer (struct fp_dev *dev,
+ fpi_ssm *ssm,
+ unsigned char endpoint,
+ unsigned char *buffer,
+ int length,
+ fpi_usb_transfer_cb_fn callback,
+ void *user_data,
+ unsigned int timeout);
+int fpi_usb_submit_transfer (fpi_usb_transfer *transfer);
+int fpi_usb_cancel_transfer (fpi_usb_transfer *transfer);
+
#endif