| Index: device/usb/usb_device_handle_impl.cc
|
| diff --git a/device/usb/usb_device_handle_impl.cc b/device/usb/usb_device_handle_impl.cc
|
| index 5bbbffe01483cb6459f561dc31c956b42da6e27a..2a03800c522d57a90203b836954b9b287de55fcc 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>
|
|
|
| @@ -119,6 +120,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
|
| @@ -190,11 +211,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();
|
|
|
| @@ -219,9 +239,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;
|
| @@ -232,6 +259,7 @@ class UsbDeviceHandleImpl::Transfer {
|
| scoped_refptr<base::SequencedTaskRunner> task_runner_;
|
| scoped_refptr<base::TaskRunner> callback_task_runner_;
|
| TransferCallback callback_;
|
| + IsochronousTransferCallback iso_callback_;
|
| };
|
|
|
| // static
|
| @@ -288,11 +316,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;
|
| }
|
| @@ -319,7 +347,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);
|
|
|
| @@ -333,20 +361,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;
|
| @@ -355,8 +379,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;
|
| }
|
| @@ -379,6 +405,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_);
|
| @@ -430,46 +471,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 */
|
| @@ -483,11 +500,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 {
|
| @@ -631,26 +674,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));
|
| }
|
| }
|
|
|
| @@ -885,33 +944,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));
|
| }
|
|
|