+static void LIBUSB_CALL receive_transfer(struct libusb_transfer *xfer);
+
+static int la2016_usbxfer_release(const struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ struct libusb_transfer *xfer;
+
+ devc = sdi ? sdi->priv : NULL;
+ if (!devc)
+ return SR_ERR_ARG;
+
+ /* Release all USB transfers. */
+ xfer = devc->transfer;
+ devc->transfer = NULL;
+ if (!xfer)
+ return SR_OK;
+
+ g_free(xfer->buffer);
+ libusb_free_transfer(xfer);
+
+ return SR_OK;
+}
+
+static int la2016_usbxfer_allocate(const struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ size_t bufsize;
+ uint8_t *buffer;
+ struct libusb_transfer *xfer;
+
+ devc = sdi ? sdi->priv : NULL;
+ if (!devc)
+ return SR_ERR_ARG;
+
+ /* Transfers were already allocated before? */
+ if (devc->transfer)
+ return SR_OK;
+
+ /*
+ * Allocate all USB transfers and their buffers. Arrange for a
+ * buffer size which is within the device's capabilities, and
+ * is a multiple of the USB endpoint's size, to make use of the
+ * RAW_IO performance feature.
+ *
+ * Implementation detail: The LA2016_USB_BUFSZ value happens
+ * to match all those constraints. No additional arithmetics is
+ * required in this location.
+ */
+ bufsize = LA2016_USB_BUFSZ;
+ buffer = g_try_malloc(bufsize);
+ if (!buffer) {
+ sr_err("Cannot allocate USB transfer buffer.");
+ return SR_ERR_MALLOC;
+ }
+ xfer = libusb_alloc_transfer(0);
+ if (!xfer) {
+ sr_err("Cannot allocate USB transfer.");
+ g_free(buffer);
+ return SR_ERR_MALLOC;
+ }
+ xfer->buffer = buffer;
+ devc->transfer = xfer;
+ devc->transfer_bufsize = bufsize;
+
+ return SR_OK;
+}
+
+static int la2016_usbxfer_cancel_all(const struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ struct libusb_transfer *xfer;
+
+ devc = sdi ? sdi->priv : NULL;
+ if (!devc)
+ return SR_ERR_ARG;
+
+ /* Unconditionally cancel the transfer. Ignore errors. */
+ xfer = devc->transfer;
+ if (xfer)
+ libusb_cancel_transfer(xfer);
+
+ return SR_OK;
+}
+
+static int la2016_usbxfer_resubmit(const struct sr_dev_inst *sdi,
+ struct libusb_transfer *xfer)
+{
+ struct dev_context *devc;
+ struct sr_usb_dev_inst *usb;
+ libusb_transfer_cb_fn cb;
+ int ret;
+
+ devc = sdi ? sdi->priv : NULL;
+ usb = sdi ? sdi->conn : NULL;
+ if (!devc || !usb)
+ return SR_ERR_ARG;
+
+ if (!xfer)
+ return SR_ERR_ARG;
+
+ cb = receive_transfer;
+ libusb_fill_bulk_transfer(xfer, usb->devhdl,
+ USB_EP_CAPTURE_DATA | LIBUSB_ENDPOINT_IN,
+ xfer->buffer, devc->transfer_bufsize,
+ cb, (void *)sdi, CAPTURE_TIMEOUT_MS);
+ ret = libusb_submit_transfer(xfer);
+ if (ret != 0) {
+ sr_err("Cannot submit USB transfer: %s.",
+ libusb_error_name(ret));
+ return SR_ERR_IO;
+ }
+
+ return SR_OK;
+}
+
+static int la2016_usbxfer_submit_all(const struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+ int ret;
+
+ devc = sdi ? sdi->priv : NULL;
+ if (!devc)
+ return SR_ERR_ARG;
+
+ ret = la2016_usbxfer_resubmit(sdi, devc->transfer);
+ if (ret != SR_OK)
+ return ret;
+
+ return SR_OK;
+}
+