| Index: extensions/browser/api/usb/usb_api.cc
|
| diff --git a/extensions/browser/api/usb/usb_api.cc b/extensions/browser/api/usb/usb_api.cc
|
| index 16710ddabbba41f9b003f5c6fed7d5b4cd442720..303523964fe927b17fff7499a5e2ef08532c86a5 100644
|
| --- a/extensions/browser/api/usb/usb_api.cc
|
| +++ b/extensions/browser/api/usb/usb_api.cc
|
| @@ -4,6 +4,8 @@
|
|
|
| #include "extensions/browser/api/usb/usb_api.h"
|
|
|
| +#include <algorithm>
|
| +#include <numeric>
|
| #include <string>
|
| #include <utility>
|
| #include <vector>
|
| @@ -468,7 +470,8 @@ void UsbTransferFunction::OnCompleted(UsbTransferStatus status,
|
| } else {
|
| scoped_ptr<base::ListValue> error_args(new base::ListValue());
|
| error_args->Append(std::move(transfer_info));
|
| - // Returning arguments with an error is wrong but we're stuck with it.
|
| + // Using ErrorWithArguments is discouraged but required to provide the
|
| + // detailed transfer info as the transfer may have partially succeeded.
|
| Respond(ErrorWithArguments(std::move(error_args),
|
| ConvertTransferStatusToApi(status)));
|
| }
|
| @@ -1134,48 +1137,89 @@ ExtensionFunction::ResponseAction UsbIsochronousTransferFunction::Run() {
|
| size_t size = 0;
|
| UsbEndpointDirection direction = device::USB_DIRECTION_INBOUND;
|
|
|
| - if (!ConvertDirectionFromApi(generic_transfer.direction, &direction)) {
|
| + if (!ConvertDirectionFromApi(generic_transfer.direction, &direction))
|
| return RespondNow(Error(kErrorConvertDirection));
|
| - }
|
|
|
| - if (!GetTransferSize(generic_transfer, &size)) {
|
| + if (!GetTransferSize(generic_transfer, &size))
|
| return RespondNow(Error(kErrorInvalidTransferLength));
|
| - }
|
|
|
| - if (transfer.packets < 0 || transfer.packets >= kMaxPackets) {
|
| + if (transfer.packets < 0 || transfer.packets >= kMaxPackets)
|
| return RespondNow(Error(kErrorInvalidNumberOfPackets));
|
| - }
|
| + size_t packets = transfer.packets;
|
|
|
| - unsigned int packets = transfer.packets;
|
| if (transfer.packet_length < 0 ||
|
| transfer.packet_length >= kMaxPacketLength) {
|
| return RespondNow(Error(kErrorInvalidPacketLength));
|
| }
|
|
|
| - unsigned int packet_length = transfer.packet_length;
|
| - const uint64_t total_length = packets * packet_length;
|
| - if (packets > size || total_length > size) {
|
| + size_t total_length = packets * transfer.packet_length;
|
| + if (packets > size || total_length > size)
|
| return RespondNow(Error(kErrorTransferLength));
|
| - }
|
| -
|
| - scoped_refptr<net::IOBuffer> buffer =
|
| - CreateBufferForTransfer(generic_transfer, direction, size);
|
| - if (!buffer.get()) {
|
| - return RespondNow(Error(kErrorMalformedParameters));
|
| - }
|
| + std::vector<uint32_t> packet_lengths(packets, transfer.packet_length);
|
|
|
| int timeout = generic_transfer.timeout ? *generic_transfer.timeout : 0;
|
| - if (timeout < 0) {
|
| + if (timeout < 0)
|
| return RespondNow(Error(kErrorInvalidTimeout));
|
| - }
|
|
|
| - device_handle->IsochronousTransfer(
|
| - direction, generic_transfer.endpoint, buffer.get(), size, packets,
|
| - packet_length, timeout,
|
| - base::Bind(&UsbIsochronousTransferFunction::OnCompleted, this));
|
| + if (direction == device::USB_DIRECTION_INBOUND) {
|
| + device_handle->IsochronousTransferIn(
|
| + generic_transfer.endpoint, packet_lengths, timeout,
|
| + base::Bind(&UsbIsochronousTransferFunction::OnCompleted, this));
|
| + } else {
|
| + scoped_refptr<net::IOBuffer> buffer = CreateBufferForTransfer(
|
| + generic_transfer, direction, transfer.packets * transfer.packet_length);
|
| + if (!buffer.get())
|
| + return RespondNow(Error(kErrorMalformedParameters));
|
| +
|
| + device_handle->IsochronousTransferOut(
|
| + generic_transfer.endpoint, buffer.get(), packet_lengths, timeout,
|
| + base::Bind(&UsbIsochronousTransferFunction::OnCompleted, this));
|
| + }
|
| return RespondLater();
|
| }
|
|
|
| +void UsbIsochronousTransferFunction::OnCompleted(
|
| + scoped_refptr<net::IOBuffer> data,
|
| + const std::vector<UsbDeviceHandle::IsochronousPacket>& packets) {
|
| + size_t length = std::accumulate(
|
| + packets.begin(), packets.end(), 0,
|
| + [](const size_t& a, const UsbDeviceHandle::IsochronousPacket& packet) {
|
| + return a + packet.transferred_length;
|
| + });
|
| + scoped_ptr<char[]> buffer(new char[length]);
|
| +
|
| + UsbTransferStatus status = device::USB_TRANSFER_COMPLETED;
|
| + size_t buffer_offset = 0;
|
| + size_t data_offset = 0;
|
| + for (const auto& packet : packets) {
|
| + // Capture the error status of the first unsuccessful packet.
|
| + if (status == device::USB_TRANSFER_COMPLETED &&
|
| + packet.status != device::USB_TRANSFER_COMPLETED) {
|
| + status = packet.status;
|
| + }
|
| +
|
| + memcpy(&buffer[buffer_offset], data->data() + data_offset,
|
| + packet.transferred_length);
|
| + buffer_offset += packet.transferred_length;
|
| + data_offset += packet.length;
|
| + }
|
| +
|
| + scoped_ptr<base::DictionaryValue> transfer_info(new base::DictionaryValue());
|
| + transfer_info->SetInteger(kResultCodeKey, status);
|
| + transfer_info->Set(kDataKey,
|
| + new base::BinaryValue(std::move(buffer), length));
|
| + if (status == device::USB_TRANSFER_COMPLETED) {
|
| + Respond(OneArgument(std::move(transfer_info)));
|
| + } else {
|
| + scoped_ptr<base::ListValue> error_args(new base::ListValue());
|
| + error_args->Append(std::move(transfer_info));
|
| + // Using ErrorWithArguments is discouraged but required to provide the
|
| + // detailed transfer info as the transfer may have partially succeeded.
|
| + Respond(ErrorWithArguments(std::move(error_args),
|
| + ConvertTransferStatusToApi(status)));
|
| + }
|
| +}
|
| +
|
| UsbResetDeviceFunction::UsbResetDeviceFunction() {
|
| }
|
|
|
| @@ -1210,7 +1254,8 @@ void UsbResetDeviceFunction::OnComplete(bool success) {
|
|
|
| scoped_ptr<base::ListValue> error_args(new base::ListValue());
|
| error_args->AppendBoolean(false);
|
| - // Returning arguments with an error is wrong but we're stuck with it.
|
| + // Using ErrorWithArguments is discouraged but required to maintain
|
| + // compatibility with existing applications.
|
| Respond(ErrorWithArguments(std::move(error_args), kErrorResetDevice));
|
| }
|
| }
|
|
|