summaryrefslogtreecommitdiffstats
path: root/device/usb
diff options
context:
space:
mode:
authorreillyg <reillyg@chromium.org>2016-02-01 16:56:15 -0800
committerCommit bot <commit-bot@chromium.org>2016-02-02 00:58:06 +0000
commit051c98e9d3e843295d659b5676fcfa9dc1be5da6 (patch)
tree54414ed43e166fb91bcfb3d6413157ad9cf27fe6 /device/usb
parentea6d840e4d96f6df739f55a89ccf69daa3569a77 (diff)
downloadchromium_src-051c98e9d3e843295d659b5676fcfa9dc1be5da6.zip
chromium_src-051c98e9d3e843295d659b5676fcfa9dc1be5da6.tar.gz
chromium_src-051c98e9d3e843295d659b5676fcfa9dc1be5da6.tar.bz2
Update device/usb and its Mojo interface for variable size ISO packets.
To support the WebUSB API our underlying USB library needs to support isochronous transfers with full control over the packet size. We also need to know the completion status of each packet which was previously not available. This patch updates the interface to match that provided by libusb and the underlying platform specific APIs. BUG=492204 Review URL: https://codereview.chromium.org/1618393004 Cr-Commit-Position: refs/heads/master@{#372844}
Diffstat (limited to 'device/usb')
-rw-r--r--device/usb/mock_usb_device_handle.h23
-rw-r--r--device/usb/usb_device_handle.h32
-rw-r--r--device/usb/usb_device_handle_impl.cc240
-rw-r--r--device/usb/usb_device_handle_impl.h35
4 files changed, 216 insertions, 114 deletions
diff --git a/device/usb/mock_usb_device_handle.h b/device/usb/mock_usb_device_handle.h
index 372068c..26e6190 100644
--- a/device/usb/mock_usb_device_handle.h
+++ b/device/usb/mock_usb_device_handle.h
@@ -5,11 +5,12 @@
#ifndef DEVICE_USB_MOCK_USB_DEVICE_HANDLE_H_
#define DEVICE_USB_MOCK_USB_DEVICE_HANDLE_H_
-#include "device/usb/usb_device_handle.h"
-
#include <stddef.h>
#include <stdint.h>
+#include <vector>
+
+#include "device/usb/usb_device_handle.h"
#include "net/base/io_buffer.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -17,7 +18,7 @@ namespace device {
class MockUsbDeviceHandle : public UsbDeviceHandle {
public:
- MockUsbDeviceHandle(UsbDevice* device);
+ explicit MockUsbDeviceHandle(UsbDevice* device);
scoped_refptr<UsbDevice> GetDevice() const override;
MOCK_METHOD0(Close, void());
@@ -44,15 +45,17 @@ class MockUsbDeviceHandle : public UsbDeviceHandle {
size_t length,
unsigned int timeout,
const TransferCallback& callback));
- MOCK_METHOD8(IsochronousTransfer,
- void(UsbEndpointDirection direction,
- uint8_t endpoint,
+ MOCK_METHOD4(IsochronousTransferIn,
+ void(uint8_t endpoint,
+ const std::vector<uint32_t>& packet_lengths,
+ unsigned int timeout,
+ const IsochronousTransferCallback& callback));
+ MOCK_METHOD5(IsochronousTransferOut,
+ void(uint8_t endpoint,
scoped_refptr<net::IOBuffer> buffer,
- size_t length,
- unsigned int packets,
- unsigned int packet_length,
+ const std::vector<uint32_t>& packet_lengths,
unsigned int timeout,
- const TransferCallback& callback));
+ const IsochronousTransferCallback& callback));
MOCK_METHOD6(GenericTransfer,
void(UsbEndpointDirection direction,
uint8_t endpoint,
diff --git a/device/usb/usb_device_handle.h b/device/usb/usb_device_handle.h
index a97dddc..b206cf1 100644
--- a/device/usb/usb_device_handle.h
+++ b/device/usb/usb_device_handle.h
@@ -40,9 +40,18 @@ enum UsbTransferStatus {
// UsbDeviceHandle class provides basic I/O related functionalities.
class UsbDeviceHandle : public base::RefCountedThreadSafe<UsbDeviceHandle> {
public:
+ struct IsochronousPacket {
+ uint32_t length;
+ uint32_t transferred_length;
+ UsbTransferStatus status;
+ };
+
using ResultCallback = base::Callback<void(bool)>;
using TransferCallback = base::Callback<
void(UsbTransferStatus, scoped_refptr<net::IOBuffer>, size_t)>;
+ using IsochronousTransferCallback =
+ base::Callback<void(scoped_refptr<net::IOBuffer>,
+ const std::vector<IsochronousPacket>& packets)>;
enum TransferRequestType { STANDARD, CLASS, VENDOR, RESERVED };
enum TransferRecipient { DEVICE, INTERFACE, ENDPOINT, OTHER };
@@ -81,17 +90,21 @@ class UsbDeviceHandle : public base::RefCountedThreadSafe<UsbDeviceHandle> {
unsigned int timeout,
const TransferCallback& callback) = 0;
- virtual void IsochronousTransfer(UsbEndpointDirection direction,
- uint8_t endpoint,
- scoped_refptr<net::IOBuffer> buffer,
- size_t length,
- unsigned int packets,
- unsigned int packet_length,
- unsigned int timeout,
- const TransferCallback& callback) = 0;
+ virtual void IsochronousTransferIn(
+ uint8_t endpoint_number,
+ const std::vector<uint32_t>& packet_lengths,
+ unsigned int timeout,
+ const IsochronousTransferCallback& callback) = 0;
+
+ virtual void IsochronousTransferOut(
+ uint8_t endpoint_number,
+ scoped_refptr<net::IOBuffer> buffer,
+ const std::vector<uint32_t>& packet_lengths,
+ unsigned int timeout,
+ const IsochronousTransferCallback& callback) = 0;
virtual void GenericTransfer(UsbEndpointDirection direction,
- uint8_t endpoint,
+ uint8_t endpoint_number,
scoped_refptr<net::IOBuffer> buffer,
size_t length,
unsigned int timeout,
@@ -109,6 +122,7 @@ class UsbDeviceHandle : public base::RefCountedThreadSafe<UsbDeviceHandle> {
virtual ~UsbDeviceHandle();
+ private:
DISALLOW_COPY_AND_ASSIGN(UsbDeviceHandle);
};
diff --git a/device/usb/usb_device_handle_impl.cc b/device/usb/usb_device_handle_impl.cc
index 338af16..fa4c085 100644
--- a/device/usb/usb_device_handle_impl.cc
+++ b/device/usb/usb_device_handle_impl.cc
@@ -5,6 +5,7 @@
#include "device/usb/usb_device_handle_impl.h"
#include <algorithm>
+#include <numeric>
#include <utility>
#include <vector>
@@ -120,6 +121,26 @@ static void RunTransferCallback(
}
}
+void ReportIsochronousTransferError(
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const UsbDeviceHandle::IsochronousTransferCallback& callback,
+ const std::vector<uint32_t> packet_lengths,
+ UsbTransferStatus status) {
+ std::vector<UsbDeviceHandle::IsochronousPacket> packets(
+ packet_lengths.size());
+ for (size_t i = 0; i < packet_lengths.size(); ++i) {
+ packets[i].length = packet_lengths[i];
+ packets[i].transferred_length = 0;
+ packets[i].status = status;
+ }
+ if (callback_task_runner->RunsTasksOnCurrentThread()) {
+ callback.Run(nullptr, packets);
+ } else {
+ callback_task_runner->PostTask(FROM_HERE,
+ base::Bind(callback, nullptr, packets));
+ }
+}
+
} // namespace
class UsbDeviceHandleImpl::InterfaceClaimer
@@ -191,11 +212,10 @@ class UsbDeviceHandleImpl::Transfer {
uint8_t endpoint,
scoped_refptr<net::IOBuffer> buffer,
size_t length,
- unsigned int packets,
- unsigned int packet_length,
+ const std::vector<uint32_t>& packet_lengths,
unsigned int timeout,
- scoped_refptr<base::TaskRunner> task_runner,
- const TransferCallback& callback);
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const IsochronousTransferCallback& callback);
~Transfer();
@@ -220,9 +240,16 @@ class UsbDeviceHandleImpl::Transfer {
size_t length,
scoped_refptr<base::TaskRunner> callback_task_runner,
const TransferCallback& callback);
+ Transfer(scoped_refptr<UsbDeviceHandleImpl> device_handle,
+ scoped_refptr<InterfaceClaimer> claimed_interface,
+ scoped_refptr<net::IOBuffer> buffer,
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const IsochronousTransferCallback& callback);
static void LIBUSB_CALL PlatformCallback(PlatformUsbTransferHandle handle);
+ void IsochronousTransferComplete();
+
UsbTransferType transfer_type_;
scoped_refptr<UsbDeviceHandleImpl> device_handle_;
PlatformUsbTransferHandle platform_transfer_ = nullptr;
@@ -233,6 +260,7 @@ class UsbDeviceHandleImpl::Transfer {
scoped_refptr<base::SequencedTaskRunner> task_runner_;
scoped_refptr<base::TaskRunner> callback_task_runner_;
TransferCallback callback_;
+ IsochronousTransferCallback iso_callback_;
};
// static
@@ -289,11 +317,11 @@ UsbDeviceHandleImpl::Transfer::CreateBulkTransfer(
return nullptr;
}
- libusb_fill_bulk_transfer(
- transfer->platform_transfer_, device_handle->handle_, endpoint,
- reinterpret_cast<uint8_t*>(buffer->data()), static_cast<int>(length),
- &UsbDeviceHandleImpl::Transfer::PlatformCallback, transfer.get(),
- timeout);
+ libusb_fill_bulk_transfer(transfer->platform_transfer_,
+ device_handle->handle_, endpoint,
+ reinterpret_cast<uint8_t*>(buffer->data()), length,
+ &UsbDeviceHandleImpl::Transfer::PlatformCallback,
+ transfer.get(), timeout);
return transfer;
}
@@ -320,7 +348,7 @@ UsbDeviceHandleImpl::Transfer::CreateInterruptTransfer(
libusb_fill_interrupt_transfer(
transfer->platform_transfer_, device_handle->handle_, endpoint,
- reinterpret_cast<uint8_t*>(buffer->data()), static_cast<int>(length),
+ reinterpret_cast<uint8_t*>(buffer->data()), length,
&UsbDeviceHandleImpl::Transfer::PlatformCallback, transfer.get(),
timeout);
@@ -334,20 +362,16 @@ UsbDeviceHandleImpl::Transfer::CreateIsochronousTransfer(
uint8_t endpoint,
scoped_refptr<net::IOBuffer> buffer,
size_t length,
- unsigned int packets,
- unsigned int packet_length,
+ const std::vector<uint32_t>& packet_lengths,
unsigned int timeout,
scoped_refptr<base::TaskRunner> callback_task_runner,
- const TransferCallback& callback) {
- DCHECK(packets <= length && (packets * packet_length) <= length)
- << "transfer length is too small";
-
+ const IsochronousTransferCallback& callback) {
scoped_ptr<Transfer> transfer(new Transfer(
device_handle, device_handle->GetClaimedInterfaceForEndpoint(endpoint),
- USB_TRANSFER_ISOCHRONOUS, buffer, length, callback_task_runner,
- callback));
+ buffer, callback_task_runner, callback));
- transfer->platform_transfer_ = libusb_alloc_transfer(packets);
+ int num_packets = static_cast<int>(packet_lengths.size());
+ transfer->platform_transfer_ = libusb_alloc_transfer(num_packets);
if (!transfer->platform_transfer_) {
USB_LOG(ERROR) << "Failed to allocate isochronous transfer.";
return nullptr;
@@ -356,8 +380,10 @@ UsbDeviceHandleImpl::Transfer::CreateIsochronousTransfer(
libusb_fill_iso_transfer(
transfer->platform_transfer_, device_handle->handle_, endpoint,
reinterpret_cast<uint8_t*>(buffer->data()), static_cast<int>(length),
- packets, &Transfer::PlatformCallback, transfer.get(), timeout);
- libusb_set_iso_packet_lengths(transfer->platform_transfer_, packet_length);
+ num_packets, &Transfer::PlatformCallback, transfer.get(), timeout);
+
+ for (size_t i = 0; i < packet_lengths.size(); ++i)
+ transfer->platform_transfer_->iso_packet_desc[i].length = packet_lengths[i];
return transfer;
}
@@ -380,6 +406,21 @@ UsbDeviceHandleImpl::Transfer::Transfer(
task_runner_ = base::ThreadTaskRunnerHandle::Get();
}
+UsbDeviceHandleImpl::Transfer::Transfer(
+ scoped_refptr<UsbDeviceHandleImpl> device_handle,
+ scoped_refptr<InterfaceClaimer> claimed_interface,
+ scoped_refptr<net::IOBuffer> buffer,
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const IsochronousTransferCallback& callback)
+ : transfer_type_(USB_TRANSFER_ISOCHRONOUS),
+ device_handle_(device_handle),
+ buffer_(buffer),
+ claimed_interface_(claimed_interface),
+ callback_task_runner_(callback_task_runner),
+ iso_callback_(callback) {
+ task_runner_ = base::ThreadTaskRunnerHandle::Get();
+}
+
UsbDeviceHandleImpl::Transfer::~Transfer() {
if (platform_transfer_) {
libusb_free_transfer(platform_transfer_);
@@ -431,46 +472,22 @@ void UsbDeviceHandleImpl::Transfer::ProcessCompletion() {
buffer_ = resized_buffer;
}
}
- break;
-
- case USB_TRANSFER_ISOCHRONOUS:
- // Isochronous replies might carry data in the different isoc packets even
- // if the transfer actual_data value is zero. Furthermore, not all of the
- // received packets might contain data, so we need to calculate how many
- // data bytes we are effectively providing and pack the results.
- if (actual_length == 0) {
- size_t packet_buffer_start = 0;
- for (int i = 0; i < platform_transfer_->num_iso_packets; ++i) {
- PlatformUsbIsoPacketDescriptor packet =
- &platform_transfer_->iso_packet_desc[i];
- if (packet->actual_length > 0) {
- // We don't need to copy as long as all packets until now provide
- // all the data the packet can hold.
- if (actual_length < packet_buffer_start) {
- CHECK(packet_buffer_start + packet->actual_length <= length_);
- memmove(buffer_->data() + actual_length,
- buffer_->data() + packet_buffer_start,
- packet->actual_length);
- }
- actual_length += packet->actual_length;
- }
-
- packet_buffer_start += packet->length;
- }
- }
- break;
+ // Fall through!
case USB_TRANSFER_BULK:
case USB_TRANSFER_INTERRUPT:
+ TransferComplete(ConvertTransferStatus(platform_transfer_->status),
+ actual_length);
+ break;
+
+ case USB_TRANSFER_ISOCHRONOUS:
+ IsochronousTransferComplete();
break;
default:
NOTREACHED() << "Invalid usb transfer type";
break;
}
-
- TransferComplete(ConvertTransferStatus(platform_transfer_->status),
- actual_length);
}
/* static */
@@ -484,11 +501,37 @@ void LIBUSB_CALL UsbDeviceHandleImpl::Transfer::PlatformCallback(
void UsbDeviceHandleImpl::Transfer::TransferComplete(UsbTransferStatus status,
size_t bytes_transferred) {
+ base::Closure closure;
+ if (transfer_type_ == USB_TRANSFER_ISOCHRONOUS) {
+ DCHECK_NE(LIBUSB_TRANSFER_COMPLETED, platform_transfer_->status);
+ std::vector<IsochronousPacket> packets(platform_transfer_->num_iso_packets);
+ for (size_t i = 0; i < packets.size(); ++i) {
+ packets[i].length = platform_transfer_->iso_packet_desc[i].length;
+ packets[i].transferred_length = 0;
+ packets[i].status = status;
+ }
+ closure = base::Bind(iso_callback_, buffer_, packets);
+ } else {
+ closure = base::Bind(callback_, status, buffer_, bytes_transferred);
+ }
task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&UsbDeviceHandleImpl::TransferComplete, device_handle_,
- base::Unretained(this),
- base::Bind(callback_, status, buffer_, bytes_transferred)));
+ FROM_HERE, base::Bind(&UsbDeviceHandleImpl::TransferComplete,
+ device_handle_, base::Unretained(this), closure));
+}
+
+void UsbDeviceHandleImpl::Transfer::IsochronousTransferComplete() {
+ std::vector<IsochronousPacket> packets(platform_transfer_->num_iso_packets);
+ for (size_t i = 0; i < packets.size(); ++i) {
+ packets[i].length = platform_transfer_->iso_packet_desc[i].length;
+ packets[i].transferred_length =
+ platform_transfer_->iso_packet_desc[i].actual_length;
+ packets[i].status =
+ ConvertTransferStatus(platform_transfer_->iso_packet_desc[i].status);
+ }
+ task_runner_->PostTask(
+ FROM_HERE, base::Bind(&UsbDeviceHandleImpl::TransferComplete,
+ device_handle_, base::Unretained(this),
+ base::Bind(iso_callback_, buffer_, packets)));
}
scoped_refptr<UsbDevice> UsbDeviceHandleImpl::GetDevice() const {
@@ -632,26 +675,42 @@ void UsbDeviceHandleImpl::ControlTransfer(UsbEndpointDirection direction,
}
}
-void UsbDeviceHandleImpl::IsochronousTransfer(
- UsbEndpointDirection direction,
+void UsbDeviceHandleImpl::IsochronousTransferIn(
+ uint8_t endpoint_number,
+ const std::vector<uint32_t>& packet_lengths,
+ unsigned int timeout,
+ const IsochronousTransferCallback& callback) {
+ uint8_t endpoint_address =
+ ConvertTransferDirection(USB_DIRECTION_INBOUND) | endpoint_number;
+ if (task_runner_->BelongsToCurrentThread()) {
+ IsochronousTransferInInternal(endpoint_address, packet_lengths, timeout,
+ task_runner_, callback);
+ } else {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UsbDeviceHandleImpl::IsochronousTransferInInternal, this,
+ endpoint_address, packet_lengths, timeout,
+ base::ThreadTaskRunnerHandle::Get(), callback));
+ }
+}
+
+void UsbDeviceHandleImpl::IsochronousTransferOut(
uint8_t endpoint_number,
scoped_refptr<net::IOBuffer> buffer,
- size_t length,
- unsigned int packets,
- unsigned int packet_length,
+ const std::vector<uint32_t>& packet_lengths,
unsigned int timeout,
- const TransferCallback& callback) {
+ const IsochronousTransferCallback& callback) {
uint8_t endpoint_address =
- ConvertTransferDirection(direction) | endpoint_number;
+ ConvertTransferDirection(USB_DIRECTION_OUTBOUND) | endpoint_number;
if (task_runner_->BelongsToCurrentThread()) {
- IsochronousTransferInternal(endpoint_address, buffer, length, packets,
- packet_length, timeout, task_runner_, callback);
+ IsochronousTransferOutInternal(endpoint_address, buffer, packet_lengths,
+ timeout, task_runner_, callback);
} else {
task_runner_->PostTask(
FROM_HERE,
- base::Bind(&UsbDeviceHandleImpl::IsochronousTransferInternal, this,
- endpoint_address, buffer, length, packets, packet_length,
- timeout, base::ThreadTaskRunnerHandle::Get(), callback));
+ base::Bind(&UsbDeviceHandleImpl::IsochronousTransferOutInternal, this,
+ endpoint_address, buffer, packet_lengths, timeout,
+ base::ThreadTaskRunnerHandle::Get(), callback));
}
}
@@ -886,33 +945,50 @@ void UsbDeviceHandleImpl::ControlTransferInternal(
SubmitTransfer(std::move(transfer));
}
-void UsbDeviceHandleImpl::IsochronousTransferInternal(
+void UsbDeviceHandleImpl::IsochronousTransferInInternal(
uint8_t endpoint_address,
- scoped_refptr<net::IOBuffer> buffer,
- size_t length,
- unsigned int packets,
- unsigned int packet_length,
+ const std::vector<uint32_t>& packet_lengths,
unsigned int timeout,
scoped_refptr<base::TaskRunner> callback_task_runner,
- const TransferCallback& callback) {
+ const IsochronousTransferCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!device_) {
- RunTransferCallback(callback_task_runner, callback, USB_TRANSFER_DISCONNECT,
- buffer, 0);
+ ReportIsochronousTransferError(callback_task_runner, callback,
+ packet_lengths, USB_TRANSFER_DISCONNECT);
return;
}
- if (!base::IsValueInRangeForNumericType<int>(length)) {
- USB_LOG(USER) << "Transfer too long.";
- RunTransferCallback(callback_task_runner, callback, USB_TRANSFER_ERROR,
- buffer, 0);
+ size_t length =
+ std::accumulate(packet_lengths.begin(), packet_lengths.end(), 0u);
+ scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(length));
+ scoped_ptr<Transfer> transfer = Transfer::CreateIsochronousTransfer(
+ this, endpoint_address, buffer, length, packet_lengths, timeout,
+ callback_task_runner, callback);
+
+ SubmitTransfer(std::move(transfer));
+}
+
+void UsbDeviceHandleImpl::IsochronousTransferOutInternal(
+ uint8_t endpoint_address,
+ scoped_refptr<net::IOBuffer> buffer,
+ const std::vector<uint32_t>& packet_lengths,
+ unsigned int timeout,
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const IsochronousTransferCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!device_) {
+ ReportIsochronousTransferError(callback_task_runner, callback,
+ packet_lengths, USB_TRANSFER_DISCONNECT);
return;
}
+ size_t length =
+ std::accumulate(packet_lengths.begin(), packet_lengths.end(), 0u);
scoped_ptr<Transfer> transfer = Transfer::CreateIsochronousTransfer(
- this, endpoint_address, buffer, static_cast<int>(length), packets,
- packet_length, timeout, callback_task_runner, callback);
+ this, endpoint_address, buffer, length, packet_lengths, timeout,
+ callback_task_runner, callback);
SubmitTransfer(std::move(transfer));
}
diff --git a/device/usb/usb_device_handle_impl.h b/device/usb/usb_device_handle_impl.h
index 7d10e42..ce2daff 100644
--- a/device/usb/usb_device_handle_impl.h
+++ b/device/usb/usb_device_handle_impl.h
@@ -71,14 +71,18 @@ class UsbDeviceHandleImpl : public UsbDeviceHandle {
unsigned int timeout,
const TransferCallback& callback) override;
- void IsochronousTransfer(UsbEndpointDirection direction,
- uint8_t endpoint_number,
- scoped_refptr<net::IOBuffer> buffer,
- size_t length,
- unsigned int packets,
- unsigned int packet_length,
- unsigned int timeout,
- const TransferCallback& callback) override;
+ void IsochronousTransferIn(
+ uint8_t endpoint,
+ const std::vector<uint32_t>& packet_lengths,
+ unsigned int timeout,
+ const IsochronousTransferCallback& callback) override;
+
+ void IsochronousTransferOut(
+ uint8_t endpoint,
+ scoped_refptr<net::IOBuffer> buffer,
+ const std::vector<uint32_t>& packet_lengths,
+ unsigned int timeout,
+ const IsochronousTransferCallback& callback) override;
void GenericTransfer(UsbEndpointDirection direction,
uint8_t endpoint_number,
@@ -149,15 +153,20 @@ class UsbDeviceHandleImpl : public UsbDeviceHandle {
scoped_refptr<base::TaskRunner> callback_task_runner,
const TransferCallback& callback);
- void IsochronousTransferInternal(
+ void IsochronousTransferInInternal(
+ uint8_t endpoint_address,
+ const std::vector<uint32_t>& packet_lengths,
+ unsigned int timeout,
+ scoped_refptr<base::TaskRunner> callback_task_runner,
+ const IsochronousTransferCallback& callback);
+
+ void IsochronousTransferOutInternal(
uint8_t endpoint_address,
scoped_refptr<net::IOBuffer> buffer,
- size_t length,
- unsigned int packets,
- unsigned int packet_length,
+ const std::vector<uint32_t>& packet_lengths,
unsigned int timeout,
scoped_refptr<base::TaskRunner> callback_task_runner,
- const TransferCallback& callback);
+ const IsochronousTransferCallback& callback);
void GenericTransferInternal(
uint8_t endpoint_address,