| // 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_api.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/memory/scoped_ptr.h" |
| #include "base/message_loop/message_loop_proxy.h" |
| #include "chrome/browser/extensions/api/usb/usb_device_resource.h" |
| #include "chrome/browser/extensions/extension_system.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/usb/usb_device_handle.h" |
| #include "chrome/browser/usb/usb_service.h" |
| #include "chrome/common/extensions/api/usb.h" |
| #include "chrome/common/extensions/permissions/permissions_data.h" |
| #include "chrome/common/extensions/permissions/usb_device_permission.h" |
| |
| namespace usb = extensions::api::usb; |
| namespace BulkTransfer = usb::BulkTransfer; |
| namespace ClaimInterface = usb::ClaimInterface; |
| namespace CloseDevice = usb::CloseDevice; |
| namespace ControlTransfer = usb::ControlTransfer; |
| namespace FindDevices = usb::FindDevices; |
| namespace GetDevices = usb::GetDevices; |
| namespace InterruptTransfer = usb::InterruptTransfer; |
| namespace IsochronousTransfer = usb::IsochronousTransfer; |
| namespace ListInterfaces = usb::ListInterfaces; |
| namespace OpenDevice = usb::OpenDevice; |
| namespace ReleaseInterface = usb::ReleaseInterface; |
| namespace RequestAccess = usb::RequestAccess; |
| namespace ResetDevice = usb::ResetDevice; |
| namespace SetInterfaceAlternateSetting = usb::SetInterfaceAlternateSetting; |
| |
| using content::BrowserThread; |
| using std::string; |
| using std::vector; |
| using usb::ControlTransferInfo; |
| using usb::ConnectionHandle; |
| using usb::Device; |
| using usb::Direction; |
| using usb::EndpointDescriptor; |
| using usb::GenericTransferInfo; |
| using usb::InterfaceDescriptor; |
| using usb::IsochronousTransferInfo; |
| using usb::Recipient; |
| using usb::RequestType; |
| using usb::SynchronizationType; |
| using usb::TransferType; |
| using usb::UsageType; |
| |
| typedef std::vector<scoped_refptr<UsbDevice> > DeviceVector; |
| typedef scoped_ptr<DeviceVector> ScopedDeviceVector; |
| |
| namespace { |
| |
| const char kDataKey[] = "data"; |
| const char kResultCodeKey[] = "resultCode"; |
| |
| const char kErrorInitService[] = "Failed to initialize USB service."; |
| |
| const char kErrorOpen[] = "Failed to open device."; |
| const char kErrorCancelled[] = "Transfer was cancelled."; |
| const char kErrorDisconnect[] = "Device disconnected."; |
| const char kErrorGeneric[] = "Transfer failed."; |
| #if !defined(OS_CHROMEOS) |
| const char kErrorNotSupported[] = "Not supported on this platform."; |
| #endif |
| const char kErrorOverflow[] = "Inbound transfer overflow."; |
| const char kErrorStalled[] = "Transfer stalled."; |
| const char kErrorTimeout[] = "Transfer timed out."; |
| const char kErrorTransferLength[] = "Transfer length is insufficient."; |
| |
| const char kErrorCannotListInterfaces[] = "Error listing interfaces."; |
| const char kErrorCannotClaimInterface[] = "Error claiming interface."; |
| const char kErrorCannotReleaseInterface[] = "Error releasing interface."; |
| const char kErrorCannotSetInterfaceAlternateSetting[] = |
| "Error setting alternate interface setting."; |
| const char kErrorConvertDirection[] = "Invalid transfer direction."; |
| const char kErrorConvertRecipient[] = "Invalid transfer recipient."; |
| const char kErrorConvertRequestType[] = "Invalid request type."; |
| const char kErrorConvertSynchronizationType[] = "Invalid synchronization type"; |
| const char kErrorConvertTransferType[] = "Invalid endpoint type."; |
| const char kErrorConvertUsageType[] = "Invalid usage type."; |
| const char kErrorMalformedParameters[] = "Error parsing parameters."; |
| const char kErrorNoDevice[] = "No such device."; |
| const char kErrorPermissionDenied[] = |
| "Permission to access device was denied"; |
| const char kErrorInvalidTransferLength[] = |
| "Transfer length must be a positive number less than 104,857,600."; |
| const char kErrorInvalidNumberOfPackets[] = |
| "Number of packets must be a positive number less than 4,194,304."; |
| const char kErrorInvalidPacketLength[] = "Packet length must be a " |
| "positive number less than 65,536."; |
| const char kErrorResetDevice[] = |
| "Error resetting the device. The device has been closed."; |
| |
| const size_t kMaxTransferLength = 100 * 1024 * 1024; |
| const int kMaxPackets = 4 * 1024 * 1024; |
| const int kMaxPacketLength = 64 * 1024; |
| |
| UsbDevice* g_device_for_test = NULL; |
| |
| bool ConvertDirectionToApi(const UsbEndpointDirection& input, |
| Direction* output) { |
| switch (input) { |
| case USB_DIRECTION_INBOUND: |
| *output = usb::DIRECTION_IN; |
| return true; |
| case USB_DIRECTION_OUTBOUND: |
| *output = usb::DIRECTION_OUT; |
| return true; |
| default: |
| NOTREACHED(); |
| return false; |
| } |
| } |
| |
| bool ConvertSynchronizationTypeToApi(const UsbSynchronizationType& input, |
| usb::SynchronizationType* output) { |
| switch (input) { |
| case USB_SYNCHRONIZATION_NONE: |
| *output = usb::SYNCHRONIZATION_TYPE_NONE; |
| return true; |
| case USB_SYNCHRONIZATION_ASYNCHRONOUS: |
| *output = usb::SYNCHRONIZATION_TYPE_ASYNCHRONOUS; |
| return true; |
| case USB_SYNCHRONIZATION_ADAPTIVE: |
| *output = usb::SYNCHRONIZATION_TYPE_ADAPTIVE; |
| return true; |
| case USB_SYNCHRONIZATION_SYNCHRONOUS: |
| *output = usb::SYNCHRONIZATION_TYPE_SYNCHRONOUS; |
| return true; |
| default: |
| NOTREACHED(); |
| return false; |
| } |
| } |
| |
| bool ConvertTransferTypeToApi( |
| const UsbTransferType& input, |
| usb::TransferType* output) { |
| switch (input) { |
| case USB_TRANSFER_CONTROL: |
| *output = usb::TRANSFER_TYPE_CONTROL; |
| return true; |
| case USB_TRANSFER_INTERRUPT: |
| *output = usb::TRANSFER_TYPE_INTERRUPT; |
| return true; |
| case USB_TRANSFER_ISOCHRONOUS: |
| *output = usb::TRANSFER_TYPE_ISOCHRONOUS; |
| return true; |
| case USB_TRANSFER_BULK: |
| *output = usb::TRANSFER_TYPE_BULK; |
| return true; |
| default: |
| NOTREACHED(); |
| return false; |
| } |
| } |
| |
| bool ConvertUsageTypeToApi(const UsbUsageType& input, usb::UsageType* output) { |
| switch (input) { |
| case USB_USAGE_DATA: |
| *output = usb::USAGE_TYPE_DATA; |
| return true; |
| case USB_USAGE_FEEDBACK: |
| *output = usb::USAGE_TYPE_FEEDBACK; |
| return true; |
| case USB_USAGE_EXPLICIT_FEEDBACK: |
| *output = usb::USAGE_TYPE_EXPLICITFEEDBACK; |
| return true; |
| default: |
| NOTREACHED(); |
| return false; |
| } |
| } |
| |
| bool ConvertDirection(const Direction& input, |
| UsbEndpointDirection* output) { |
| switch (input) { |
| case usb::DIRECTION_IN: |
| *output = USB_DIRECTION_INBOUND; |
| return true; |
| case usb::DIRECTION_OUT: |
| *output = USB_DIRECTION_OUTBOUND; |
| return true; |
| default: |
| NOTREACHED(); |
| return false; |
| } |
| } |
| |
| bool ConvertRequestType(const RequestType& input, |
| UsbDeviceHandle::TransferRequestType* output) { |
| switch (input) { |
| case usb::REQUEST_TYPE_STANDARD: |
| *output = UsbDeviceHandle::STANDARD; |
| return true; |
| case usb::REQUEST_TYPE_CLASS: |
| *output = UsbDeviceHandle::CLASS; |
| return true; |
| case usb::REQUEST_TYPE_VENDOR: |
| *output = UsbDeviceHandle::VENDOR; |
| return true; |
| case usb::REQUEST_TYPE_RESERVED: |
| *output = UsbDeviceHandle::RESERVED; |
| return true; |
| default: |
| NOTREACHED(); |
| return false; |
| } |
| } |
| |
| bool ConvertRecipient(const Recipient& input, |
| UsbDeviceHandle::TransferRecipient* output) { |
| switch (input) { |
| case usb::RECIPIENT_DEVICE: |
| *output = UsbDeviceHandle::DEVICE; |
| return true; |
| case usb::RECIPIENT_INTERFACE: |
| *output = UsbDeviceHandle::INTERFACE; |
| return true; |
| case usb::RECIPIENT_ENDPOINT: |
| *output = UsbDeviceHandle::ENDPOINT; |
| return true; |
| case usb::RECIPIENT_OTHER: |
| *output = UsbDeviceHandle::OTHER; |
| return true; |
| default: |
| NOTREACHED(); |
| return false; |
| } |
| } |
| |
| template<class T> |
| bool GetTransferSize(const T& input, size_t* output) { |
| if (input.direction == usb::DIRECTION_IN) { |
| const int* length = input.length.get(); |
| if (length && *length >= 0 && |
| static_cast<size_t>(*length) < kMaxTransferLength) { |
| *output = *length; |
| return true; |
| } |
| } else if (input.direction == usb::DIRECTION_OUT) { |
| if (input.data.get()) { |
| *output = input.data->size(); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| template<class T> |
| scoped_refptr<net::IOBuffer> CreateBufferForTransfer( |
| const T& input, UsbEndpointDirection direction, size_t size) { |
| |
| if (size >= kMaxTransferLength) |
| return NULL; |
| |
| // Allocate a |size|-bytes buffer, or a one-byte buffer if |size| is 0. This |
| // is due to an impedance mismatch between IOBuffer and URBs. An IOBuffer |
| // cannot represent a zero-length buffer, while an URB can. |
| scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(std::max( |
| static_cast<size_t>(1), size)); |
| |
| if (direction == USB_DIRECTION_INBOUND) { |
| return buffer; |
| } else if (direction == USB_DIRECTION_OUTBOUND) { |
| if (input.data.get() && size <= input.data->size()) { |
| memcpy(buffer->data(), input.data->data(), size); |
| return buffer; |
| } |
| } |
| NOTREACHED(); |
| return NULL; |
| } |
| |
| const char* ConvertTransferStatusToErrorString(const UsbTransferStatus status) { |
| switch (status) { |
| case USB_TRANSFER_COMPLETED: |
| return ""; |
| case USB_TRANSFER_ERROR: |
| return kErrorGeneric; |
| case USB_TRANSFER_TIMEOUT: |
| return kErrorTimeout; |
| case USB_TRANSFER_CANCELLED: |
| return kErrorCancelled; |
| case USB_TRANSFER_STALLED: |
| return kErrorStalled; |
| case USB_TRANSFER_DISCONNECT: |
| return kErrorDisconnect; |
| case USB_TRANSFER_OVERFLOW: |
| return kErrorOverflow; |
| case USB_TRANSFER_LENGTH_SHORT: |
| return kErrorTransferLength; |
| default: |
| NOTREACHED(); |
| return ""; |
| } |
| } |
| |
| #if defined(OS_CHROMEOS) |
| void RequestUsbDevicesAccessHelper( |
| ScopedDeviceVector devices, |
| std::vector<scoped_refptr<UsbDevice> >::iterator i, |
| int interface_id, |
| const base::Callback<void(ScopedDeviceVector result)>& callback, |
| bool success) { |
| if (success) { |
| ++i; |
| } else { |
| i = devices->erase(i); |
| } |
| if (i == devices->end()) { |
| callback.Run(devices.Pass()); |
| return; |
| } |
| (*i)->RequestUsbAcess(interface_id, base::Bind(RequestUsbDevicesAccessHelper, |
| base::Passed(devices.Pass()), |
| i, interface_id, callback)); |
| } |
| |
| void RequestUsbDevicesAccess( |
| ScopedDeviceVector devices, |
| int interface_id, |
| const base::Callback<void(ScopedDeviceVector result)>& callback) { |
| if (devices->empty()) { |
| callback.Run(devices.Pass()); |
| return; |
| } |
| std::vector<scoped_refptr<UsbDevice> >::iterator i = devices->begin(); |
| (*i)->RequestUsbAcess( |
| interface_id, |
| base::Bind(RequestUsbDevicesAccessHelper, base::Passed(devices.Pass()), |
| i, interface_id, callback)); |
| } |
| #endif // OS_CHROMEOS |
| |
| base::DictionaryValue* CreateTransferInfo( |
| UsbTransferStatus status, |
| scoped_refptr<net::IOBuffer> data, |
| size_t length) { |
| base::DictionaryValue* result = new base::DictionaryValue(); |
| result->SetInteger(kResultCodeKey, status); |
| result->Set(kDataKey, base::BinaryValue::CreateWithCopiedBuffer(data->data(), |
| length)); |
| return result; |
| } |
| |
| base::Value* PopulateConnectionHandle(int handle, int vendor_id, |
| int product_id) { |
| ConnectionHandle result; |
| result.handle = handle; |
| result.vendor_id = vendor_id; |
| result.product_id = product_id; |
| return result.ToValue().release(); |
| } |
| |
| base::Value* PopulateDevice(UsbDevice* device) { |
| Device result; |
| result.device = device->unique_id(); |
| result.vendor_id = device->vendor_id(); |
| result.product_id = device->product_id(); |
| return result.ToValue().release(); |
| } |
| |
| base::Value* PopulateInterfaceDescriptor( |
| int interface_number, |
| int alternate_setting, |
| int interface_class, |
| int interface_subclass, |
| int interface_protocol, |
| std::vector<linked_ptr<EndpointDescriptor> >* endpoints) { |
| InterfaceDescriptor descriptor; |
| descriptor.interface_number = interface_number; |
| descriptor.alternate_setting = alternate_setting; |
| descriptor.interface_class = interface_class; |
| descriptor.interface_subclass = interface_subclass; |
| descriptor.interface_protocol = interface_protocol; |
| descriptor.endpoints = *endpoints; |
| return descriptor.ToValue().release(); |
| } |
| |
| } // namespace |
| |
| namespace extensions { |
| |
| UsbAsyncApiFunction::UsbAsyncApiFunction() |
| : manager_(NULL) { |
| } |
| |
| UsbAsyncApiFunction::~UsbAsyncApiFunction() { |
| } |
| |
| bool UsbAsyncApiFunction::PrePrepare() { |
| manager_ = ApiResourceManager<UsbDeviceResource>::Get(GetProfile()); |
| set_work_thread_id(BrowserThread::FILE); |
| return manager_ != NULL; |
| } |
| |
| bool UsbAsyncApiFunction::Respond() { |
| return error_.empty(); |
| } |
| |
| scoped_refptr<UsbDevice> |
| UsbAsyncApiFunction::GetDeviceOrOrCompleteWithError( |
| const Device& input_device) { |
| if (g_device_for_test) |
| return g_device_for_test; |
| |
| const uint16_t vendor_id = input_device.vendor_id; |
| const uint16_t product_id = input_device.product_id; |
| UsbDevicePermission::CheckParam param( |
| vendor_id, product_id, UsbDevicePermissionData::UNSPECIFIED_INTERFACE); |
| if (!PermissionsData::CheckAPIPermissionWithParam( |
| GetExtension(), APIPermission::kUsbDevice, ¶m)) { |
| LOG(WARNING) << "Insufficient permissions to access device."; |
| CompleteWithError(kErrorPermissionDenied); |
| return NULL; |
| } |
| |
| UsbService* service = UsbService::GetInstance(); |
| if (!service) { |
| CompleteWithError(kErrorInitService); |
| return NULL; |
| } |
| scoped_refptr<UsbDevice> device; |
| |
| device = service->GetDeviceById(input_device.device); |
| |
| if (!device) { |
| CompleteWithError(kErrorNoDevice); |
| return NULL; |
| } |
| |
| if (device->vendor_id() != input_device.vendor_id || |
| device->product_id() != input_device.product_id) { |
| // Must act as if there is no such a device. |
| // Otherwise can be used to finger print unauthorized devices. |
| CompleteWithError(kErrorNoDevice); |
| return NULL; |
| } |
| |
| return device; |
| } |
| |
| scoped_refptr<UsbDeviceHandle> |
| UsbAsyncApiFunction::GetDeviceHandleOrCompleteWithError( |
| const ConnectionHandle& input_device_handle) { |
| UsbDeviceResource* resource = |
| manager_->Get(extension_->id(), input_device_handle.handle); |
| if (!resource) { |
| CompleteWithError(kErrorNoDevice); |
| return NULL; |
| } |
| |
| if (!resource->device() || !resource->device()->device()) { |
| CompleteWithError(kErrorDisconnect); |
| manager_->Remove(extension_->id(), input_device_handle.handle); |
| return NULL; |
| } |
| |
| if (resource->device()->device()->vendor_id() != |
| input_device_handle.vendor_id || |
| resource->device()->device()->product_id() != |
| input_device_handle.product_id) { |
| CompleteWithError(kErrorNoDevice); |
| return NULL; |
| } |
| |
| return resource->device(); |
| } |
| |
| void UsbAsyncApiFunction::RemoveUsbDeviceResource(int api_resource_id) { |
| manager_->Remove(extension_->id(), api_resource_id); |
| } |
| |
| void UsbAsyncApiFunction::CompleteWithError(const std::string& error) { |
| SetError(error); |
| AsyncWorkCompleted(); |
| } |
| |
| UsbAsyncApiTransferFunction::UsbAsyncApiTransferFunction() {} |
| |
| UsbAsyncApiTransferFunction::~UsbAsyncApiTransferFunction() {} |
| |
| void UsbAsyncApiTransferFunction::OnCompleted(UsbTransferStatus status, |
| scoped_refptr<net::IOBuffer> data, |
| size_t length) { |
| if (status != USB_TRANSFER_COMPLETED) |
| SetError(ConvertTransferStatusToErrorString(status)); |
| |
| SetResult(CreateTransferInfo(status, data, length)); |
| AsyncWorkCompleted(); |
| } |
| |
| bool UsbAsyncApiTransferFunction::ConvertDirectionSafely( |
| const Direction& input, UsbEndpointDirection* output) { |
| const bool converted = ConvertDirection(input, output); |
| if (!converted) |
| SetError(kErrorConvertDirection); |
| return converted; |
| } |
| |
| bool UsbAsyncApiTransferFunction::ConvertRequestTypeSafely( |
| const RequestType& input, UsbDeviceHandle::TransferRequestType* output) { |
| const bool converted = ConvertRequestType(input, output); |
| if (!converted) |
| SetError(kErrorConvertRequestType); |
| return converted; |
| } |
| |
| bool UsbAsyncApiTransferFunction::ConvertRecipientSafely( |
| const Recipient& input, UsbDeviceHandle::TransferRecipient* output) { |
| const bool converted = ConvertRecipient(input, output); |
| if (!converted) |
| SetError(kErrorConvertRecipient); |
| return converted; |
| } |
| |
| UsbFindDevicesFunction::UsbFindDevicesFunction() {} |
| |
| UsbFindDevicesFunction::~UsbFindDevicesFunction() {} |
| |
| bool UsbFindDevicesFunction::Prepare() { |
| parameters_ = FindDevices::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters_.get()); |
| return true; |
| } |
| |
| void UsbFindDevicesFunction::AsyncWorkStart() { |
| scoped_ptr<base::ListValue> result(new base::ListValue()); |
| |
| if (g_device_for_test) { |
| UsbDeviceResource* const resource = new UsbDeviceResource( |
| extension_->id(), |
| g_device_for_test->Open()); |
| |
| result->Append(PopulateConnectionHandle(manager_->Add(resource), 0, 0)); |
| SetResult(result.release()); |
| AsyncWorkCompleted(); |
| return; |
| } |
| |
| const uint16_t vendor_id = parameters_->options.vendor_id; |
| const uint16_t product_id = parameters_->options.product_id; |
| int interface_id = parameters_->options.interface_id.get() ? |
| *parameters_->options.interface_id.get() : |
| UsbDevicePermissionData::ANY_INTERFACE; |
| UsbDevicePermission::CheckParam param(vendor_id, product_id, interface_id); |
| if (!PermissionsData::CheckAPIPermissionWithParam( |
| GetExtension(), APIPermission::kUsbDevice, ¶m)) { |
| LOG(WARNING) << "Insufficient permissions to access device."; |
| CompleteWithError(kErrorPermissionDenied); |
| return; |
| } |
| |
| UsbService *service = UsbService::GetInstance(); |
| if (!service) { |
| CompleteWithError(kErrorInitService); |
| return; |
| } |
| |
| ScopedDeviceVector devices(new DeviceVector()); |
| service->GetDevices(devices.get()); |
| |
| for (DeviceVector::iterator it = devices->begin(); |
| it != devices->end();) { |
| if ((*it)->vendor_id() != vendor_id || (*it)->product_id() != product_id) { |
| it = devices->erase(it); |
| } else { |
| ++it; |
| } |
| } |
| |
| #if defined(OS_CHROMEOS) |
| RequestUsbDevicesAccess( |
| devices.Pass(), interface_id, |
| base::Bind(&UsbFindDevicesFunction::OpenDevices, this)); |
| #else |
| OpenDevices(devices.Pass()); |
| #endif // OS_CHROMEOS |
| } |
| |
| void UsbFindDevicesFunction::OpenDevices(ScopedDeviceVector devices) { |
| base::ListValue* result = new base::ListValue(); |
| |
| for (size_t i = 0; i < devices->size(); ++i) { |
| scoped_refptr<UsbDeviceHandle> device_handle = |
| devices->at(i)->Open(); |
| if (device_handle) |
| device_handles_.push_back(device_handle); |
| } |
| |
| for (size_t i = 0; i < device_handles_.size(); ++i) { |
| UsbDeviceHandle* const device_handle = device_handles_[i].get(); |
| UsbDeviceResource* const resource = |
| new UsbDeviceResource(extension_->id(), device_handle); |
| |
| result->Append(PopulateConnectionHandle(manager_->Add(resource), |
| parameters_->options.vendor_id, |
| parameters_->options.product_id)); |
| } |
| |
| SetResult(result); |
| AsyncWorkCompleted(); |
| } |
| |
| UsbGetDevicesFunction::UsbGetDevicesFunction() { |
| } |
| |
| UsbGetDevicesFunction::~UsbGetDevicesFunction() { |
| } |
| |
| void UsbGetDevicesFunction::SetDeviceForTest(UsbDevice* device) { |
| g_device_for_test = device; |
| } |
| |
| bool UsbGetDevicesFunction::Prepare() { |
| parameters_ = GetDevices::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters_.get()); |
| return true; |
| } |
| |
| void UsbGetDevicesFunction::AsyncWorkStart() { |
| scoped_ptr<base::ListValue> result(new base::ListValue()); |
| |
| if (g_device_for_test) { |
| result->Append(PopulateDevice(g_device_for_test)); |
| SetResult(result.release()); |
| AsyncWorkCompleted(); |
| return; |
| } |
| |
| const uint16_t vendor_id = parameters_->options.vendor_id; |
| const uint16_t product_id = parameters_->options.product_id; |
| UsbDevicePermission::CheckParam param( |
| vendor_id, product_id, UsbDevicePermissionData::UNSPECIFIED_INTERFACE); |
| if (!PermissionsData::CheckAPIPermissionWithParam( |
| GetExtension(), APIPermission::kUsbDevice, ¶m)) { |
| LOG(WARNING) << "Insufficient permissions to access device."; |
| CompleteWithError(kErrorPermissionDenied); |
| return; |
| } |
| |
| UsbService* service = UsbService::GetInstance(); |
| if (!service) { |
| CompleteWithError(kErrorInitService); |
| return; |
| } |
| |
| DeviceVector devices; |
| service->GetDevices(&devices); |
| |
| for (DeviceVector::iterator it = devices.begin(); it != devices.end();) { |
| if ((*it)->vendor_id() != vendor_id || (*it)->product_id() != product_id) { |
| it = devices.erase(it); |
| } else { |
| ++it; |
| } |
| } |
| |
| for (size_t i = 0; i < devices.size(); ++i) { |
| result->Append(PopulateDevice(devices[i].get())); |
| } |
| |
| SetResult(result.release()); |
| AsyncWorkCompleted(); |
| } |
| |
| UsbRequestAccessFunction::UsbRequestAccessFunction() {} |
| |
| UsbRequestAccessFunction::~UsbRequestAccessFunction() {} |
| |
| bool UsbRequestAccessFunction::Prepare() { |
| parameters_ = RequestAccess::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters_.get()); |
| return true; |
| } |
| |
| void UsbRequestAccessFunction::AsyncWorkStart() { |
| #if defined(OS_CHROMEOS) |
| scoped_refptr<UsbDevice> device = |
| GetDeviceOrOrCompleteWithError(parameters_->device); |
| if (!device) return; |
| |
| device->RequestUsbAcess(parameters_->interface_id, |
| base::Bind(&UsbRequestAccessFunction::OnCompleted, |
| this)); |
| #else |
| SetResult(new base::FundamentalValue(false)); |
| CompleteWithError(kErrorNotSupported); |
| #endif // OS_CHROMEOS |
| } |
| |
| void UsbRequestAccessFunction::OnCompleted(bool success) { |
| SetResult(new base::FundamentalValue(success)); |
| AsyncWorkCompleted(); |
| } |
| |
| UsbOpenDeviceFunction::UsbOpenDeviceFunction() {} |
| |
| UsbOpenDeviceFunction::~UsbOpenDeviceFunction() {} |
| |
| bool UsbOpenDeviceFunction::Prepare() { |
| parameters_ = OpenDevice::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters_.get()); |
| return true; |
| } |
| |
| void UsbOpenDeviceFunction::AsyncWorkStart() { |
| scoped_refptr<UsbDevice> device = |
| GetDeviceOrOrCompleteWithError(parameters_->device); |
| if (!device) return; |
| |
| handle_ = device->Open(); |
| if (!handle_) { |
| SetError(kErrorOpen); |
| AsyncWorkCompleted(); |
| return; |
| } |
| |
| SetResult(PopulateConnectionHandle( |
| manager_->Add(new UsbDeviceResource(extension_->id(), handle_)), |
| handle_->device()->vendor_id(), |
| handle_->device()->product_id())); |
| AsyncWorkCompleted(); |
| } |
| |
| UsbListInterfacesFunction::UsbListInterfacesFunction() {} |
| |
| UsbListInterfacesFunction::~UsbListInterfacesFunction() {} |
| |
| bool UsbListInterfacesFunction::Prepare() { |
| parameters_ = ListInterfaces::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters_.get()); |
| return true; |
| } |
| |
| void UsbListInterfacesFunction::AsyncWorkStart() { |
| scoped_refptr<UsbDeviceHandle> device_handle = |
| GetDeviceHandleOrCompleteWithError(parameters_->handle); |
| if (!device_handle) return; |
| |
| scoped_refptr<UsbConfigDescriptor> config = |
| device_handle->device()->ListInterfaces(); |
| |
| if (!config) { |
| SetError(kErrorCannotListInterfaces); |
| AsyncWorkCompleted(); |
| return; |
| } |
| |
| result_.reset(new base::ListValue()); |
| |
| for (size_t i = 0, num_interfaces = config->GetNumInterfaces(); |
| i < num_interfaces; ++i) { |
| scoped_refptr<const UsbInterfaceDescriptor> |
| usb_interface(config->GetInterface(i)); |
| for (size_t j = 0, num_descriptors = usb_interface->GetNumAltSettings(); |
| j < num_descriptors; ++j) { |
| scoped_refptr<const UsbInterfaceAltSettingDescriptor> descriptor |
| = usb_interface->GetAltSetting(j); |
| std::vector<linked_ptr<EndpointDescriptor> > endpoints; |
| for (size_t k = 0, num_endpoints = descriptor->GetNumEndpoints(); |
| k < num_endpoints; k++) { |
| scoped_refptr<const UsbEndpointDescriptor> endpoint |
| = descriptor->GetEndpoint(k); |
| linked_ptr<EndpointDescriptor> endpoint_desc(new EndpointDescriptor()); |
| |
| TransferType type; |
| Direction direction; |
| SynchronizationType synchronization; |
| UsageType usage; |
| |
| if (!ConvertTransferTypeSafely(endpoint->GetTransferType(), &type) || |
| !ConvertDirectionSafely(endpoint->GetDirection(), &direction) || |
| !ConvertSynchronizationTypeSafely( |
| endpoint->GetSynchronizationType(), &synchronization) || |
| !ConvertUsageTypeSafely(endpoint->GetUsageType(), &usage)) { |
| SetError(kErrorCannotListInterfaces); |
| AsyncWorkCompleted(); |
| return; |
| } |
| |
| endpoint_desc->address = endpoint->GetAddress(); |
| endpoint_desc->type = type; |
| endpoint_desc->direction = direction; |
| endpoint_desc->maximum_packet_size = endpoint->GetMaximumPacketSize(); |
| endpoint_desc->synchronization = synchronization; |
| endpoint_desc->usage = usage; |
| |
| int* polling_interval = new int; |
| endpoint_desc->polling_interval.reset(polling_interval); |
| *polling_interval = endpoint->GetPollingInterval(); |
| |
| endpoints.push_back(endpoint_desc); |
| } |
| |
| result_->Append(PopulateInterfaceDescriptor( |
| descriptor->GetInterfaceNumber(), |
| descriptor->GetAlternateSetting(), |
| descriptor->GetInterfaceClass(), |
| descriptor->GetInterfaceSubclass(), |
| descriptor->GetInterfaceProtocol(), |
| &endpoints)); |
| } |
| } |
| |
| SetResult(result_.release()); |
| AsyncWorkCompleted(); |
| } |
| |
| bool UsbListInterfacesFunction::ConvertDirectionSafely( |
| const UsbEndpointDirection& input, |
| usb::Direction* output) { |
| const bool converted = ConvertDirectionToApi(input, output); |
| if (!converted) |
| SetError(kErrorConvertDirection); |
| return converted; |
| } |
| |
| bool UsbListInterfacesFunction::ConvertSynchronizationTypeSafely( |
| const UsbSynchronizationType& input, |
| usb::SynchronizationType* output) { |
| const bool converted = ConvertSynchronizationTypeToApi(input, output); |
| if (!converted) |
| SetError(kErrorConvertSynchronizationType); |
| return converted; |
| } |
| |
| bool UsbListInterfacesFunction::ConvertTransferTypeSafely( |
| const UsbTransferType& input, |
| usb::TransferType* output) { |
| const bool converted = ConvertTransferTypeToApi(input, output); |
| if (!converted) |
| SetError(kErrorConvertTransferType); |
| return converted; |
| } |
| |
| bool UsbListInterfacesFunction::ConvertUsageTypeSafely( |
| const UsbUsageType& input, |
| usb::UsageType* output) { |
| const bool converted = ConvertUsageTypeToApi(input, output); |
| if (!converted) |
| SetError(kErrorConvertUsageType); |
| return converted; |
| } |
| |
| UsbCloseDeviceFunction::UsbCloseDeviceFunction() {} |
| |
| UsbCloseDeviceFunction::~UsbCloseDeviceFunction() {} |
| |
| bool UsbCloseDeviceFunction::Prepare() { |
| parameters_ = CloseDevice::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters_.get()); |
| return true; |
| } |
| |
| void UsbCloseDeviceFunction::AsyncWorkStart() { |
| scoped_refptr<UsbDeviceHandle> device_handle = |
| GetDeviceHandleOrCompleteWithError(parameters_->handle); |
| if (!device_handle) return; |
| |
| device_handle->Close(); |
| RemoveUsbDeviceResource(parameters_->handle.handle); |
| AsyncWorkCompleted(); |
| } |
| |
| UsbClaimInterfaceFunction::UsbClaimInterfaceFunction() {} |
| |
| UsbClaimInterfaceFunction::~UsbClaimInterfaceFunction() {} |
| |
| bool UsbClaimInterfaceFunction::Prepare() { |
| parameters_ = ClaimInterface::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters_.get()); |
| return true; |
| } |
| |
| void UsbClaimInterfaceFunction::AsyncWorkStart() { |
| scoped_refptr<UsbDeviceHandle> device_handle = |
| GetDeviceHandleOrCompleteWithError(parameters_->handle); |
| if (!device_handle) return; |
| |
| bool success = device_handle->ClaimInterface(parameters_->interface_number); |
| |
| if (!success) |
| SetError(kErrorCannotClaimInterface); |
| AsyncWorkCompleted(); |
| } |
| |
| UsbReleaseInterfaceFunction::UsbReleaseInterfaceFunction() {} |
| |
| UsbReleaseInterfaceFunction::~UsbReleaseInterfaceFunction() {} |
| |
| bool UsbReleaseInterfaceFunction::Prepare() { |
| parameters_ = ReleaseInterface::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters_.get()); |
| return true; |
| } |
| |
| void UsbReleaseInterfaceFunction::AsyncWorkStart() { |
| scoped_refptr<UsbDeviceHandle> device_handle = |
| GetDeviceHandleOrCompleteWithError(parameters_->handle); |
| if (!device_handle) return; |
| |
| bool success = device_handle->ReleaseInterface(parameters_->interface_number); |
| if (!success) |
| SetError(kErrorCannotReleaseInterface); |
| AsyncWorkCompleted(); |
| } |
| |
| UsbSetInterfaceAlternateSettingFunction:: |
| UsbSetInterfaceAlternateSettingFunction() {} |
| |
| UsbSetInterfaceAlternateSettingFunction:: |
| ~UsbSetInterfaceAlternateSettingFunction() {} |
| |
| bool UsbSetInterfaceAlternateSettingFunction::Prepare() { |
| parameters_ = SetInterfaceAlternateSetting::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters_.get()); |
| return true; |
| } |
| |
| void UsbSetInterfaceAlternateSettingFunction::AsyncWorkStart() { |
| scoped_refptr<UsbDeviceHandle> device_handle = |
| GetDeviceHandleOrCompleteWithError(parameters_->handle); |
| if (!device_handle) return; |
| |
| bool success = device_handle->SetInterfaceAlternateSetting( |
| parameters_->interface_number, |
| parameters_->alternate_setting); |
| if (!success) |
| SetError(kErrorCannotSetInterfaceAlternateSetting); |
| |
| AsyncWorkCompleted(); |
| } |
| |
| UsbControlTransferFunction::UsbControlTransferFunction() {} |
| |
| UsbControlTransferFunction::~UsbControlTransferFunction() {} |
| |
| bool UsbControlTransferFunction::Prepare() { |
| parameters_ = ControlTransfer::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters_.get()); |
| return true; |
| } |
| |
| void UsbControlTransferFunction::AsyncWorkStart() { |
| scoped_refptr<UsbDeviceHandle> device_handle = |
| GetDeviceHandleOrCompleteWithError(parameters_->handle); |
| if (!device_handle) return; |
| |
| const ControlTransferInfo& transfer = parameters_->transfer_info; |
| |
| UsbEndpointDirection direction; |
| UsbDeviceHandle::TransferRequestType request_type; |
| UsbDeviceHandle::TransferRecipient recipient; |
| size_t size = 0; |
| |
| if (!ConvertDirectionSafely(transfer.direction, &direction) || |
| !ConvertRequestTypeSafely(transfer.request_type, &request_type) || |
| !ConvertRecipientSafely(transfer.recipient, &recipient)) { |
| AsyncWorkCompleted(); |
| return; |
| } |
| |
| if (!GetTransferSize(transfer, &size)) { |
| CompleteWithError(kErrorInvalidTransferLength); |
| return; |
| } |
| |
| scoped_refptr<net::IOBuffer> buffer = CreateBufferForTransfer( |
| transfer, direction, size); |
| if (!buffer.get()) { |
| CompleteWithError(kErrorMalformedParameters); |
| return; |
| } |
| |
| device_handle->ControlTransfer( |
| direction, |
| request_type, |
| recipient, |
| transfer.request, |
| transfer.value, |
| transfer.index, |
| buffer.get(), |
| size, |
| 0, |
| base::Bind(&UsbControlTransferFunction::OnCompleted, this)); |
| } |
| |
| UsbBulkTransferFunction::UsbBulkTransferFunction() {} |
| |
| UsbBulkTransferFunction::~UsbBulkTransferFunction() {} |
| |
| bool UsbBulkTransferFunction::Prepare() { |
| parameters_ = BulkTransfer::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters_.get()); |
| return true; |
| } |
| |
| void UsbBulkTransferFunction::AsyncWorkStart() { |
| scoped_refptr<UsbDeviceHandle> device_handle = |
| GetDeviceHandleOrCompleteWithError(parameters_->handle); |
| if (!device_handle) return; |
| |
| const GenericTransferInfo& transfer = parameters_->transfer_info; |
| |
| UsbEndpointDirection direction; |
| size_t size = 0; |
| |
| if (!ConvertDirectionSafely(transfer.direction, &direction)) { |
| AsyncWorkCompleted(); |
| return; |
| } |
| |
| if (!GetTransferSize(transfer, &size)) { |
| CompleteWithError(kErrorInvalidTransferLength); |
| return; |
| } |
| |
| scoped_refptr<net::IOBuffer> buffer = CreateBufferForTransfer( |
| transfer, direction, size); |
| if (!buffer.get()) { |
| CompleteWithError(kErrorMalformedParameters); |
| return; |
| } |
| |
| device_handle->BulkTransfer( |
| direction, |
| transfer.endpoint, |
| buffer.get(), |
| size, |
| 0, |
| base::Bind(&UsbBulkTransferFunction::OnCompleted, this)); |
| } |
| |
| UsbInterruptTransferFunction::UsbInterruptTransferFunction() {} |
| |
| UsbInterruptTransferFunction::~UsbInterruptTransferFunction() {} |
| |
| bool UsbInterruptTransferFunction::Prepare() { |
| parameters_ = InterruptTransfer::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters_.get()); |
| return true; |
| } |
| |
| void UsbInterruptTransferFunction::AsyncWorkStart() { |
| scoped_refptr<UsbDeviceHandle> device_handle = |
| GetDeviceHandleOrCompleteWithError(parameters_->handle); |
| if (!device_handle) return; |
| |
| const GenericTransferInfo& transfer = parameters_->transfer_info; |
| |
| UsbEndpointDirection direction; |
| size_t size = 0; |
| |
| if (!ConvertDirectionSafely(transfer.direction, &direction)) { |
| AsyncWorkCompleted(); |
| return; |
| } |
| |
| if (!GetTransferSize(transfer, &size)) { |
| CompleteWithError(kErrorInvalidTransferLength); |
| return; |
| } |
| |
| scoped_refptr<net::IOBuffer> buffer = CreateBufferForTransfer( |
| transfer, direction, size); |
| if (!buffer.get()) { |
| CompleteWithError(kErrorMalformedParameters); |
| return; |
| } |
| |
| device_handle->InterruptTransfer( |
| direction, |
| transfer.endpoint, |
| buffer.get(), |
| size, |
| 0, |
| base::Bind(&UsbInterruptTransferFunction::OnCompleted, this)); |
| } |
| |
| UsbIsochronousTransferFunction::UsbIsochronousTransferFunction() {} |
| |
| UsbIsochronousTransferFunction::~UsbIsochronousTransferFunction() {} |
| |
| bool UsbIsochronousTransferFunction::Prepare() { |
| parameters_ = IsochronousTransfer::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters_.get()); |
| return true; |
| } |
| |
| void UsbIsochronousTransferFunction::AsyncWorkStart() { |
| scoped_refptr<UsbDeviceHandle> device_handle = |
| GetDeviceHandleOrCompleteWithError(parameters_->handle); |
| if (!device_handle) return; |
| |
| const IsochronousTransferInfo& transfer = parameters_->transfer_info; |
| const GenericTransferInfo& generic_transfer = transfer.transfer_info; |
| |
| size_t size = 0; |
| UsbEndpointDirection direction; |
| |
| if (!ConvertDirectionSafely(generic_transfer.direction, &direction)) { |
| AsyncWorkCompleted(); |
| return; |
| } |
| if (!GetTransferSize(generic_transfer, &size)) { |
| CompleteWithError(kErrorInvalidTransferLength); |
| return; |
| } |
| if (transfer.packets < 0 || transfer.packets >= kMaxPackets) { |
| CompleteWithError(kErrorInvalidNumberOfPackets); |
| return; |
| } |
| unsigned int packets = transfer.packets; |
| if (transfer.packet_length < 0 || |
| transfer.packet_length >= kMaxPacketLength) { |
| CompleteWithError(kErrorInvalidPacketLength); |
| return; |
| } |
| unsigned int packet_length = transfer.packet_length; |
| const uint64 total_length = packets * packet_length; |
| if (packets > size || total_length > size) { |
| CompleteWithError(kErrorTransferLength); |
| return; |
| } |
| |
| scoped_refptr<net::IOBuffer> buffer = CreateBufferForTransfer( |
| generic_transfer, direction, size); |
| if (!buffer.get()) { |
| CompleteWithError(kErrorMalformedParameters); |
| return; |
| } |
| |
| device_handle->IsochronousTransfer( |
| direction, |
| generic_transfer.endpoint, |
| buffer.get(), |
| size, |
| packets, |
| packet_length, |
| 0, |
| base::Bind(&UsbIsochronousTransferFunction::OnCompleted, this)); |
| } |
| |
| UsbResetDeviceFunction::UsbResetDeviceFunction() {} |
| |
| UsbResetDeviceFunction::~UsbResetDeviceFunction() {} |
| |
| bool UsbResetDeviceFunction::Prepare() { |
| parameters_ = ResetDevice::Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(parameters_.get()); |
| return true; |
| } |
| |
| void UsbResetDeviceFunction::AsyncWorkStart() { |
| scoped_refptr<UsbDeviceHandle> device_handle = |
| GetDeviceHandleOrCompleteWithError(parameters_->handle); |
| if (!device_handle) return; |
| |
| bool success = device_handle->ResetDevice(); |
| if (!success) { |
| device_handle->Close(); |
| RemoveUsbDeviceResource(parameters_->handle.handle); |
| SetResult(new base::FundamentalValue(false)); |
| CompleteWithError(kErrorResetDevice); |
| return; |
| } |
| |
| SetResult(new base::FundamentalValue(true)); |
| AsyncWorkCompleted(); |
| } |
| |
| } // namespace extensions |