// Copyright 2014 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 "extensions/browser/api/usb/usb_api.h" #include #include #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop_proxy.h" #include "device/core/device_client.h" #include "device/usb/usb_device_handle.h" #include "device/usb/usb_service.h" #include "extensions/browser/api/device_permissions_manager.h" #include "extensions/browser/api/device_permissions_prompt.h" #include "extensions/browser/api/extensions_api_client.h" #include "extensions/browser/api/usb/usb_device_resource.h" #include "extensions/browser/extension_system.h" #include "extensions/common/api/usb.h" #include "extensions/common/permissions/permissions_data.h" #include "extensions/common/permissions/usb_device_permission.h" namespace usb = extensions::core_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 GetUserSelectedDevices = usb::GetUserSelectedDevices; namespace InterruptTransfer = usb::InterruptTransfer; namespace IsochronousTransfer = usb::IsochronousTransfer; namespace GetConfiguration = usb::GetConfiguration; 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 device::UsbConfigDescriptor; using device::UsbDevice; using device::UsbDeviceFilter; using device::UsbDeviceHandle; using device::UsbEndpointDescriptor; using device::UsbEndpointDirection; using device::UsbInterfaceDescriptor; using device::UsbService; using device::UsbSynchronizationType; using device::UsbTransferStatus; using device::UsbTransferType; using device::UsbUsageType; using std::string; using std::vector; using usb::ConfigDescriptor; 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 > DeviceVector; typedef scoped_ptr 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."; const char kErrorNotSupported[] = "Not supported on this platform."; 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 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 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; bool ConvertDirectionFromApi(const Direction& input, UsbEndpointDirection* output) { switch (input) { case usb::DIRECTION_IN: *output = device::USB_DIRECTION_INBOUND; return true; case usb::DIRECTION_OUT: *output = device::USB_DIRECTION_OUTBOUND; return true; default: NOTREACHED(); return false; } } bool ConvertRequestTypeFromApi(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 ConvertRecipientFromApi(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 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(*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 scoped_refptr 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 buffer = new net::IOBuffer(std::max(static_cast(1), size)); if (direction == device::USB_DIRECTION_INBOUND) { return buffer; } else if (direction == device::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* ConvertTransferStatusToApi(const UsbTransferStatus status) { switch (status) { case device::USB_TRANSFER_COMPLETED: return ""; case device::USB_TRANSFER_ERROR: return kErrorGeneric; case device::USB_TRANSFER_TIMEOUT: return kErrorTimeout; case device::USB_TRANSFER_CANCELLED: return kErrorCancelled; case device::USB_TRANSFER_STALLED: return kErrorStalled; case device::USB_TRANSFER_DISCONNECT: return kErrorDisconnect; case device::USB_TRANSFER_OVERFLOW: return kErrorOverflow; case device::USB_TRANSFER_LENGTH_SHORT: return kErrorTransferLength; default: NOTREACHED(); return ""; } } #if defined(OS_CHROMEOS) void RequestUsbDevicesAccessHelper( ScopedDeviceVector devices, std::vector >::iterator i, int interface_id, const base::Callback& callback, bool success) { if (success) { ++i; } else { i = devices->erase(i); } if (i == devices->end()) { callback.Run(devices.Pass()); return; } (*i)->RequestUsbAccess(interface_id, base::Bind(RequestUsbDevicesAccessHelper, base::Passed(devices.Pass()), i, interface_id, callback)); } void RequestUsbDevicesAccess( ScopedDeviceVector devices, int interface_id, const base::Callback& callback) { if (devices->empty()) { callback.Run(devices.Pass()); return; } std::vector >::iterator i = devices->begin(); (*i)->RequestUsbAccess(interface_id, base::Bind(RequestUsbDevicesAccessHelper, base::Passed(devices.Pass()), i, interface_id, callback)); } #endif // OS_CHROMEOS base::DictionaryValue* CreateTransferInfo(UsbTransferStatus status, scoped_refptr 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(const 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(); } TransferType ConvertTransferTypeToApi(const UsbTransferType& input) { switch (input) { case device::USB_TRANSFER_CONTROL: return usb::TRANSFER_TYPE_CONTROL; case device::USB_TRANSFER_INTERRUPT: return usb::TRANSFER_TYPE_INTERRUPT; case device::USB_TRANSFER_ISOCHRONOUS: return usb::TRANSFER_TYPE_ISOCHRONOUS; case device::USB_TRANSFER_BULK: return usb::TRANSFER_TYPE_BULK; default: NOTREACHED(); return usb::TRANSFER_TYPE_NONE; } } Direction ConvertDirectionToApi(const UsbEndpointDirection& input) { switch (input) { case device::USB_DIRECTION_INBOUND: return usb::DIRECTION_IN; case device::USB_DIRECTION_OUTBOUND: return usb::DIRECTION_OUT; default: NOTREACHED(); return usb::DIRECTION_NONE; } } SynchronizationType ConvertSynchronizationTypeToApi( const UsbSynchronizationType& input) { switch (input) { case device::USB_SYNCHRONIZATION_NONE: return usb::SYNCHRONIZATION_TYPE_NONE; case device::USB_SYNCHRONIZATION_ASYNCHRONOUS: return usb::SYNCHRONIZATION_TYPE_ASYNCHRONOUS; case device::USB_SYNCHRONIZATION_ADAPTIVE: return usb::SYNCHRONIZATION_TYPE_ADAPTIVE; case device::USB_SYNCHRONIZATION_SYNCHRONOUS: return usb::SYNCHRONIZATION_TYPE_SYNCHRONOUS; default: NOTREACHED(); return usb::SYNCHRONIZATION_TYPE_NONE; } } UsageType ConvertUsageTypeToApi(const UsbUsageType& input) { switch (input) { case device::USB_USAGE_DATA: return usb::USAGE_TYPE_DATA; case device::USB_USAGE_FEEDBACK: return usb::USAGE_TYPE_FEEDBACK; case device::USB_USAGE_EXPLICIT_FEEDBACK: return usb::USAGE_TYPE_EXPLICITFEEDBACK; default: NOTREACHED(); return usb::USAGE_TYPE_NONE; } } void ConvertEndpointDescriptor(const UsbEndpointDescriptor& input, EndpointDescriptor* output) { output->address = input.address; output->type = ConvertTransferTypeToApi(input.transfer_type); output->direction = ConvertDirectionToApi(input.direction); output->maximum_packet_size = input.maximum_packet_size; output->synchronization = ConvertSynchronizationTypeToApi(input.synchronization_type); output->usage = ConvertUsageTypeToApi(input.usage_type); output->polling_interval.reset(new int(input.polling_interval)); if (input.extra_data.size() > 0) { output->extra_data = std::string(reinterpret_cast(&input.extra_data[0]), input.extra_data.size()); } } void ConvertInterfaceDescriptor(const UsbInterfaceDescriptor& input, InterfaceDescriptor* output) { output->interface_number = input.interface_number; output->alternate_setting = input.alternate_setting; output->interface_class = input.interface_class; output->interface_subclass = input.interface_subclass; output->interface_protocol = input.interface_protocol; for (UsbEndpointDescriptor::Iterator endpointIt = input.endpoints.begin(); endpointIt != input.endpoints.end(); ++endpointIt) { linked_ptr endpoint(new EndpointDescriptor); ConvertEndpointDescriptor(*endpointIt, endpoint.get()); output->endpoints.push_back(endpoint); } if (input.extra_data.size() > 0) { output->extra_data = std::string(reinterpret_cast(&input.extra_data[0]), input.extra_data.size()); } } void ConvertConfigDescriptor(const UsbConfigDescriptor& input, ConfigDescriptor* output) { output->configuration_value = input.configuration_value; output->self_powered = input.self_powered; output->remote_wakeup = input.remote_wakeup; output->max_power = input.maximum_power; for (UsbInterfaceDescriptor::Iterator interfaceIt = input.interfaces.begin(); interfaceIt != input.interfaces.end(); ++interfaceIt) { linked_ptr interface(new InterfaceDescriptor); ConvertInterfaceDescriptor(*interfaceIt, interface.get()); output->interfaces.push_back(interface); } if (input.extra_data.size() > 0) { output->extra_data = std::string(reinterpret_cast(&input.extra_data[0]), input.extra_data.size()); } } void ConvertDeviceFilter(const usb::DeviceFilter& input, UsbDeviceFilter* output) { if (input.vendor_id) { output->SetVendorId(*input.vendor_id); } if (input.product_id) { output->SetProductId(*input.product_id); } if (input.interface_class) { output->SetInterfaceClass(*input.interface_class); } if (input.interface_subclass) { output->SetInterfaceSubclass(*input.interface_subclass); } if (input.interface_protocol) { output->SetInterfaceProtocol(*input.interface_protocol); } } } // namespace namespace extensions { UsbAsyncApiFunction::UsbAsyncApiFunction() : manager_(NULL) { } UsbAsyncApiFunction::~UsbAsyncApiFunction() { } bool UsbAsyncApiFunction::PrePrepare() { manager_ = ApiResourceManager::Get(browser_context()); set_work_thread_id(BrowserThread::FILE); return manager_ != NULL; } bool UsbAsyncApiFunction::Respond() { return error_.empty(); } bool UsbAsyncApiFunction::HasDevicePermission(scoped_refptr device) { DCHECK(device_permissions_); // Check the DevicePermissionsManager first so that if an entry is found // it can be stored for later. permission_entry_ = device_permissions_->FindEntry(device); if (permission_entry_.get()) { return true; } UsbDevicePermission::CheckParam param( device->vendor_id(), device->product_id(), UsbDevicePermissionData::UNSPECIFIED_INTERFACE); if (extension()->permissions_data()->CheckAPIPermissionWithParam( APIPermission::kUsbDevice, ¶m)) { return true; } return false; } scoped_refptr 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().get() || !resource->device()->GetDevice().get()) { CompleteWithError(kErrorDisconnect); manager_->Remove(extension_->id(), input_device_handle.handle); return NULL; } if (resource->device()->GetDevice()->vendor_id() != input_device_handle.vendor_id || resource->device()->GetDevice()->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 data, size_t length) { if (status != device::USB_TRANSFER_COMPLETED) SetError(ConvertTransferStatusToApi(status)); SetResult(CreateTransferInfo(status, data, length)); AsyncWorkCompleted(); } bool UsbAsyncApiTransferFunction::ConvertDirectionSafely( const Direction& input, UsbEndpointDirection* output) { const bool converted = ConvertDirectionFromApi(input, output); if (!converted) SetError(kErrorConvertDirection); return converted; } bool UsbAsyncApiTransferFunction::ConvertRequestTypeSafely( const RequestType& input, UsbDeviceHandle::TransferRequestType* output) { const bool converted = ConvertRequestTypeFromApi(input, output); if (!converted) SetError(kErrorConvertRequestType); return converted; } bool UsbAsyncApiTransferFunction::ConvertRecipientSafely( const Recipient& input, UsbDeviceHandle::TransferRecipient* output) { const bool converted = ConvertRecipientFromApi(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 result(new base::ListValue()); 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 (!extension()->permissions_data()->CheckAPIPermissionWithParam( APIPermission::kUsbDevice, ¶m)) { LOG(WARNING) << "Insufficient permissions to access device."; CompleteWithError(kErrorPermissionDenied); return; } UsbService* service = device::DeviceClient::Get()->GetUsbService(); 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 device_handle = devices->at(i)->Open(); if (device_handle.get()) 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() { } bool UsbGetDevicesFunction::Prepare() { parameters_ = GetDevices::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters_.get()); device_permissions_ = DevicePermissionsManager::Get(browser_context()) ->GetForExtension(extension()->id()); return true; } void UsbGetDevicesFunction::AsyncWorkStart() { std::vector filters; if (parameters_->options.filters) { filters.resize(parameters_->options.filters->size()); for (size_t i = 0; i < parameters_->options.filters->size(); ++i) { ConvertDeviceFilter(*parameters_->options.filters->at(i).get(), &filters[i]); } } if (parameters_->options.vendor_id) { filters.resize(filters.size() + 1); filters.back().SetVendorId(*parameters_->options.vendor_id); if (parameters_->options.product_id) { filters.back().SetProductId(*parameters_->options.product_id); } } UsbService* service = device::DeviceClient::Get()->GetUsbService(); if (!service) { CompleteWithError(kErrorInitService); return; } DeviceVector devices; service->GetDevices(&devices); scoped_ptr result(new base::ListValue()); for (DeviceVector::iterator it = devices.begin(); it != devices.end(); ++it) { scoped_refptr device = *it; if ((filters.empty() || UsbDeviceFilter::MatchesAny(device, filters)) && HasDevicePermission(device)) { result->Append(PopulateDevice(it->get())); } } SetResult(result.release()); AsyncWorkCompleted(); } UsbGetUserSelectedDevicesFunction::UsbGetUserSelectedDevicesFunction() { } UsbGetUserSelectedDevicesFunction::~UsbGetUserSelectedDevicesFunction() { } AsyncApiFunction::ResponseAction UsbGetUserSelectedDevicesFunction::Run() { scoped_ptr parameters = GetUserSelectedDevices::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); if (!user_gesture()) { return RespondNow(OneArgument(new base::ListValue())); } bool multiple = false; if (parameters->options.multiple) { multiple = *parameters->options.multiple; } std::vector filters; if (parameters->options.filters) { filters.resize(parameters->options.filters->size()); for (size_t i = 0; i < parameters->options.filters->size(); ++i) { ConvertDeviceFilter(*parameters->options.filters->at(i).get(), &filters[i]); } } prompt_ = ExtensionsAPIClient::Get()->CreateDevicePermissionsPrompt( GetAssociatedWebContents()); if (!prompt_) { return RespondNow(Error(kErrorNotSupported)); } AddRef(); prompt_->AskForUsbDevices( this, extension(), browser_context(), multiple, filters); return RespondLater(); } void UsbGetUserSelectedDevicesFunction::OnUsbDevicesChosen( const std::vector>& devices) { scoped_ptr result(new base::ListValue()); for (const auto& device : devices) { result->Append(PopulateDevice(device.get())); } SetResult(result.release()); SendResponse(true); Release(); } UsbRequestAccessFunction::UsbRequestAccessFunction() { } UsbRequestAccessFunction::~UsbRequestAccessFunction() { } bool UsbRequestAccessFunction::Prepare() { parameters_ = RequestAccess::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters_.get()); return true; } void UsbRequestAccessFunction::AsyncWorkStart() { SetResult(new base::FundamentalValue(true)); AsyncWorkCompleted(); } UsbOpenDeviceFunction::UsbOpenDeviceFunction() { } UsbOpenDeviceFunction::~UsbOpenDeviceFunction() { } bool UsbOpenDeviceFunction::Prepare() { parameters_ = OpenDevice::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters_.get()); device_permissions_manager_ = DevicePermissionsManager::Get(browser_context()); device_permissions_ = device_permissions_manager_->GetForExtension(extension()->id()); return true; } void UsbOpenDeviceFunction::AsyncWorkStart() { UsbService* service = device::DeviceClient::Get()->GetUsbService(); if (!service) { CompleteWithError(kErrorInitService); return; } device_ = service->GetDeviceById(parameters_->device.device); if (!device_.get()) { CompleteWithError(kErrorNoDevice); return; } if (!HasDevicePermission(device_)) { // This function must act as if there is no such device. Otherwise it can be // used to fingerprint unauthorized devices. CompleteWithError(kErrorNoDevice); return; } #if defined(OS_CHROMEOS) device_->RequestUsbAccess( -1, /* any interface, unused by the permission broker */ base::Bind(&UsbOpenDeviceFunction::OnRequestAccessComplete, this)); #else OnRequestAccessComplete(true); #endif // OS_CHROMEOS } void UsbOpenDeviceFunction::OnRequestAccessComplete(bool success) { if (!success) { SetError(kErrorPermissionDenied); AsyncWorkCompleted(); return; } scoped_refptr handle = device_->Open(); if (!handle.get()) { SetError(kErrorOpen); AsyncWorkCompleted(); return; } SetResult(PopulateConnectionHandle( manager_->Add(new UsbDeviceResource(extension_->id(), handle)), device_->vendor_id(), device_->product_id())); AsyncWorkCompleted(); } bool UsbOpenDeviceFunction::Respond() { if (permission_entry_.get()) { device_permissions_manager_->UpdateLastUsed(extension_->id(), permission_entry_); } return UsbAsyncApiFunction::Respond(); } UsbGetConfigurationFunction::UsbGetConfigurationFunction() { } UsbGetConfigurationFunction::~UsbGetConfigurationFunction() { } bool UsbGetConfigurationFunction::Prepare() { parameters_ = GetConfiguration::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters_.get()); return true; } void UsbGetConfigurationFunction::AsyncWorkStart() { scoped_refptr device_handle = GetDeviceHandleOrCompleteWithError(parameters_->handle); if (!device_handle.get()) { return; } ConfigDescriptor config; ConvertConfigDescriptor(device_handle->GetDevice()->GetConfiguration(), &config); SetResult(config.ToValue().release()); 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 device_handle = GetDeviceHandleOrCompleteWithError(parameters_->handle); if (!device_handle.get()) { return; } ConfigDescriptor config; ConvertConfigDescriptor(device_handle->GetDevice()->GetConfiguration(), &config); scoped_ptr result(new base::ListValue); for (size_t i = 0; i < config.interfaces.size(); ++i) { result->Append(config.interfaces[i]->ToValue().release()); } SetResult(result.release()); AsyncWorkCompleted(); } UsbCloseDeviceFunction::UsbCloseDeviceFunction() { } UsbCloseDeviceFunction::~UsbCloseDeviceFunction() { } bool UsbCloseDeviceFunction::Prepare() { parameters_ = CloseDevice::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters_.get()); return true; } void UsbCloseDeviceFunction::AsyncWorkStart() { scoped_refptr device_handle = GetDeviceHandleOrCompleteWithError(parameters_->handle); if (!device_handle.get()) 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 device_handle = GetDeviceHandleOrCompleteWithError(parameters_->handle); if (!device_handle.get()) 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 device_handle = GetDeviceHandleOrCompleteWithError(parameters_->handle); if (!device_handle.get()) 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 device_handle = GetDeviceHandleOrCompleteWithError(parameters_->handle); if (!device_handle.get()) 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 device_handle = GetDeviceHandleOrCompleteWithError(parameters_->handle); if (!device_handle.get()) 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 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 device_handle = GetDeviceHandleOrCompleteWithError(parameters_->handle); if (!device_handle.get()) 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 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 device_handle = GetDeviceHandleOrCompleteWithError(parameters_->handle); if (!device_handle.get()) 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 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 device_handle = GetDeviceHandleOrCompleteWithError(parameters_->handle); if (!device_handle.get()) 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 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 device_handle = GetDeviceHandleOrCompleteWithError(parameters_->handle); if (!device_handle.get()) 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