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 338af1663b9aff190db2ce63aa9b19bffe9c8f44..fa4c08544ff53997e053f31fbc4b79febb274455 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)); |
} |