Index: chrome/browser/extensions/api/usb/usb_device_resource.cc |
diff --git a/chrome/browser/extensions/api/usb/usb_device_resource.cc b/chrome/browser/extensions/api/usb/usb_device_resource.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c123c09039ec0baed9713a604371056da9085b28 |
--- /dev/null |
+++ b/chrome/browser/extensions/api/usb/usb_device_resource.cc |
@@ -0,0 +1,204 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/extensions/api/usb/usb_device_resource.h" |
+ |
+#include <string> |
+#include <vector> |
+ |
+#include "base/bind.h" |
+#include "base/bind_helpers.h" |
+#include "base/synchronization/lock.h" |
+#include "chrome/browser/extensions/api/api_resource_event_notifier.h" |
+#include "chrome/browser/extensions/api/api_resource.h" |
+#include "chrome/browser/usb/usb_device.h" |
+#include "chrome/common/extensions/api/experimental.usb.h" |
+ |
+using extensions::api::experimental_usb::ControlTransferInfo; |
+using extensions::api::experimental_usb::GenericTransferInfo; |
+using std::string; |
+using std::vector; |
+ |
+static const char *kDirectionIn = "in"; |
+static const char *kDirectionOut = "out"; |
+ |
+static const char *kRequestTypeStandard = "standard"; |
+static const char *kRequestTypeClass = "class"; |
+static const char *kRequestTypeVendor = "vendor"; |
+static const char *kRequestTypeReserved = "reserved"; |
+ |
+static const char *kRecipientDevice = "device"; |
+static const char *kRecipientInterface = "interface"; |
+static const char *kRecipientEndpoint = "endpoint"; |
+static const char *kRecipientOther = "other"; |
+ |
+namespace { |
+ |
+static bool ConvertDirection(const string &input, |
+ UsbDevice::TransferDirection *output) { |
+ if (input == kDirectionIn) { |
+ *output = UsbDevice::IN; |
+ return true; |
+ } else if (input == kDirectionOut) { |
+ *output = UsbDevice::OUT; |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+static bool ConvertRequestType(const string &input, |
+ UsbDevice::TransferRequestType *output) { |
+ if (input == kRequestTypeStandard) { |
+ *output = UsbDevice::STANDARD; |
+ return true; |
+ } else if (input == kRequestTypeClass) { |
+ *output = UsbDevice::CLASS; |
+ return true; |
+ } else if (input == kRequestTypeVendor) { |
+ *output = UsbDevice::VENDOR; |
+ return true; |
+ } else if (input == kRequestTypeReserved) { |
+ *output = UsbDevice::RESERVED; |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+static bool ConvertRecipient(const string &input, |
+ UsbDevice::TransferRecipient *output) { |
+ if (input == kRecipientDevice) { |
+ *output = UsbDevice::DEVICE; |
+ return true; |
+ } else if (input == kRecipientInterface) { |
+ *output = UsbDevice::INTERFACE; |
+ return true; |
+ } else if (input == kRecipientEndpoint) { |
+ *output = UsbDevice::ENDPOINT; |
+ return true; |
+ } else if (input == kRecipientOther) { |
+ *output = UsbDevice::OTHER; |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+template<class T> |
+static bool GetTransferSize(const T &input, unsigned int *output) { |
+ if (input.direction == kDirectionIn) { |
+ const int *length = input.length.get(); |
+ if (length) { |
+ *output = *length; |
+ return true; |
+ } |
+ } else if (input.direction == kDirectionOut) { |
+ if (input.data.get()) { |
+ *output = input.data->size(); |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+template<class T> |
+static scoped_refptr<net::IOBuffer> CreateBufferForTransfer(const T &input) { |
+ unsigned int size = 0; |
+ if (!GetTransferSize(input, &size)) { |
+ return NULL; |
+ } |
+ |
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(size); |
+ if (!input.data.get()) { |
+ return buffer; |
+ } |
+ |
+ const vector<int> &input_buffer = *input.data.get(); |
+ for (unsigned int i = 0; i < size; ++i) { |
+ buffer->data()[i] = input_buffer[i]; |
+ } |
+ |
+ return buffer; |
+} |
+ |
+} // namespace |
+ |
+namespace extensions { |
+ |
+UsbDeviceResource::UsbDeviceResource(APIResourceEventNotifier *notifier, |
+ UsbDevice *device) |
+ : APIResource(APIResource::UsbDeviceResource, notifier), device_(device), |
+ pending_transfers_(0) {} |
+ |
+UsbDeviceResource::~UsbDeviceResource() { |
+ if (pending_transfers_) { |
+ LOG(ERROR) << "There are transfers still in flight."; |
+ } |
+} |
+ |
+void UsbDeviceResource::ControlTransfer(const ControlTransferInfo &transfer) { |
+ UsbDevice::TransferDirection direction; |
+ UsbDevice::TransferRequestType request_type; |
+ UsbDevice::TransferRecipient recipient; |
+ unsigned int size; |
+ scoped_refptr<net::IOBuffer> buffer = CreateBufferForTransfer(transfer); |
+ |
+ if (!ConvertDirection(transfer.direction, &direction) || |
+ !ConvertRequestType(transfer.request_type, &request_type) || |
+ !ConvertRecipient(transfer.recipient, &recipient) || |
+ !GetTransferSize(transfer, &size) || !buffer) { |
+ LOG(INFO) << "Malformed transfer parameters."; |
+ return; |
+ } |
+ |
+ device_->ControlTransfer(direction, request_type, recipient, transfer.request, |
+ transfer.value, transfer.index, buffer, size, 0, |
+ base::Bind(&UsbDeviceResource::TransferComplete, |
+ base::Unretained(this), buffer, size)); |
+} |
+ |
+void UsbDeviceResource::InterruptTransfer(const GenericTransferInfo &transfer) { |
+ unsigned int size; |
+ UsbDevice::TransferDirection direction; |
+ scoped_refptr<net::IOBuffer> buffer = CreateBufferForTransfer(transfer); |
+ |
+ if (!ConvertDirection(transfer.direction, &direction) || |
+ !GetTransferSize(transfer, &size) || !buffer) { |
+ LOG(INFO) << "Malformed transfer parameters."; |
+ return; |
+ } |
+ |
+ device_->InterruptTransfer(direction, transfer.endpoint, buffer, size, 0, |
+ base::Bind(&UsbDeviceResource::TransferComplete, |
+ base::Unretained(this), buffer, size)); |
+} |
+ |
+void UsbDeviceResource::BulkTransfer(const GenericTransferInfo &transfer) { |
+ unsigned int size; |
+ UsbDevice::TransferDirection direction; |
+ scoped_refptr<net::IOBuffer> buffer = CreateBufferForTransfer(transfer); |
+ |
+ if (!ConvertDirection(transfer.direction, &direction) || |
+ !GetTransferSize(transfer, &size) || !buffer) { |
+ LOG(INFO) << "Malformed transfer parameters."; |
+ return; |
+ } |
+ |
+ device_->BulkTransfer(direction, transfer.endpoint, buffer, size, 0, |
+ base::Bind(&UsbDeviceResource::TransferComplete, |
+ base::Unretained(this), buffer, size)); |
+} |
+ |
+void UsbDeviceResource::TransferComplete(net::IOBuffer *buffer, |
+ const size_t length, |
+ int success) { |
+ if (buffer) { |
+ base::ListValue *const response_buffer = new base::ListValue(); |
+ for (unsigned int i = 0; i < length; ++i) { |
+ const uint8_t value = buffer->data()[i] & 0xFF; |
+ response_buffer->Append(base::Value::CreateIntegerValue(value)); |
+ } |
+ event_notifier()->OnTransferComplete(success, response_buffer); |
+ } |
+} |
+ |
+} // namespace extensions |