// 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/barrier_closure.h" #include "base/memory/scoped_ptr.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 SetConfiguration = usb::SetConfiguration; 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; 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 kErrorNotConfigured[] = "The device is not in a configured state."; 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 kErrorCannotSetConfiguration[] = "Error setting device configuration."; 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 kErrorNoConnection[] = "No such connection."; 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 kErrorInvalidTimeout[] = "Transfer timeout must be greater than or equal to 0."; 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 ""; } } 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)); output->extra_data.assign(input.extra_data.begin(), input.extra_data.end()); } 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 (const UsbEndpointDescriptor& input_endpoint : input.endpoints) { linked_ptr endpoint(new EndpointDescriptor); ConvertEndpointDescriptor(input_endpoint, endpoint.get()); output->endpoints.push_back(endpoint); } output->extra_data.assign(input.extra_data.begin(), input.extra_data.end()); } 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 (const UsbInterfaceDescriptor& input_interface : input.interfaces) { linked_ptr interface(new InterfaceDescriptor); ConvertInterfaceDescriptor(input_interface, interface.get()); output->interfaces.push_back(interface); } output->extra_data.assign(input.extra_data.begin(), input.extra_data.end()); } 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 { UsbPermissionCheckingFunction::UsbPermissionCheckingFunction() : device_permissions_manager_(nullptr) { } UsbPermissionCheckingFunction::~UsbPermissionCheckingFunction() { } bool UsbPermissionCheckingFunction::HasDevicePermission( scoped_refptr device) { if (!device_permissions_manager_) { device_permissions_manager_ = DevicePermissionsManager::Get(browser_context()); } DevicePermissions* device_permissions = device_permissions_manager_->GetForExtension(extension_id()); DCHECK(device_permissions); permission_entry_ = device_permissions->FindUsbDeviceEntry(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; } void UsbPermissionCheckingFunction::RecordDeviceLastUsed() { if (permission_entry_.get()) { device_permissions_manager_->UpdateLastUsed(extension_id(), permission_entry_); } } UsbConnectionFunction::UsbConnectionFunction() { } UsbConnectionFunction::~UsbConnectionFunction() { } scoped_refptr UsbConnectionFunction::GetDeviceHandle( const extensions::core_api::usb::ConnectionHandle& handle) { ApiResourceManager* manager = ApiResourceManager::Get(browser_context()); if (!manager) { return nullptr; } UsbDeviceResource* resource = manager->Get(extension_id(), handle.handle); if (!resource) { return nullptr; } return resource->device(); } void UsbConnectionFunction::ReleaseDeviceHandle( const extensions::core_api::usb::ConnectionHandle& handle) { ApiResourceManager* manager = ApiResourceManager::Get(browser_context()); manager->Remove(extension_id(), handle.handle); } UsbTransferFunction::UsbTransferFunction() { } UsbTransferFunction::~UsbTransferFunction() { } void UsbTransferFunction::OnCompleted(UsbTransferStatus status, scoped_refptr data, size_t length) { scoped_ptr transfer_info(new base::DictionaryValue()); transfer_info->SetInteger(kResultCodeKey, status); transfer_info->Set(kDataKey, base::BinaryValue::CreateWithCopiedBuffer( data->data(), length)); if (status == device::USB_TRANSFER_COMPLETED) { Respond(OneArgument(transfer_info.release())); } else { scoped_ptr error_args(new base::ListValue()); error_args->Append(transfer_info.release()); // Returning arguments with an error is wrong but we're stuck with it. Respond(ErrorWithArguments(error_args.Pass(), ConvertTransferStatusToApi(status))); } } UsbFindDevicesFunction::UsbFindDevicesFunction() { } UsbFindDevicesFunction::~UsbFindDevicesFunction() { } ExtensionFunction::ResponseAction UsbFindDevicesFunction::Run() { scoped_ptr parameters = FindDevices::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); vendor_id_ = parameters->options.vendor_id; product_id_ = parameters->options.product_id; 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)) { return RespondNow(Error(kErrorPermissionDenied)); } UsbService* service = device::DeviceClient::Get()->GetUsbService(); if (!service) { return RespondNow(Error(kErrorInitService)); } service->GetDevices( base::Bind(&UsbFindDevicesFunction::OnGetDevicesComplete, this)); return RespondLater(); } void UsbFindDevicesFunction::OnGetDevicesComplete( const std::vector>& devices) { result_.reset(new base::ListValue()); barrier_ = base::BarrierClosure( devices.size(), base::Bind(&UsbFindDevicesFunction::OpenComplete, this)); for (const scoped_refptr& device : devices) { if (device->vendor_id() != vendor_id_ || device->product_id() != product_id_) { barrier_.Run(); } else { device->RequestUsbAccess( interface_id_, base::Bind(&UsbFindDevicesFunction::OnRequestAccessComplete, this, device)); } } } void UsbFindDevicesFunction::OnRequestAccessComplete( scoped_refptr device, bool success) { if (success) { device->Open(base::Bind(&UsbFindDevicesFunction::OnDeviceOpened, this)); } else { barrier_.Run(); } } void UsbFindDevicesFunction::OnDeviceOpened( scoped_refptr device_handle) { if (device_handle.get()) { ApiResourceManager* manager = ApiResourceManager::Get(browser_context()); UsbDeviceResource* resource = new UsbDeviceResource(extension_id(), device_handle); scoped_refptr device = device_handle->GetDevice(); result_->Append(PopulateConnectionHandle( manager->Add(resource), device->vendor_id(), device->product_id())); } barrier_.Run(); } void UsbFindDevicesFunction::OpenComplete() { Respond(OneArgument(result_.release())); } UsbGetDevicesFunction::UsbGetDevicesFunction() { } UsbGetDevicesFunction::~UsbGetDevicesFunction() { } ExtensionFunction::ResponseAction UsbGetDevicesFunction::Run() { scoped_ptr parameters = GetDevices::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); 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) { return RespondNow(Error(kErrorInitService)); } service->GetDevices( base::Bind(&UsbGetDevicesFunction::OnGetDevicesComplete, this)); return RespondLater(); } void UsbGetDevicesFunction::OnGetDevicesComplete( const std::vector>& devices) { scoped_ptr result(new base::ListValue()); for (const scoped_refptr& device : devices) { if ((filters_.empty() || UsbDeviceFilter::MatchesAny(device, filters_)) && HasDevicePermission(device)) { result->Append(PopulateDevice(device.get())); } } Respond(OneArgument(result.release())); } UsbGetUserSelectedDevicesFunction::UsbGetUserSelectedDevicesFunction() { } UsbGetUserSelectedDevicesFunction::~UsbGetUserSelectedDevicesFunction() { } ExtensionFunction::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)); } prompt_->AskForUsbDevices( extension(), browser_context(), multiple, filters, base::Bind(&UsbGetUserSelectedDevicesFunction::OnDevicesChosen, this)); return RespondLater(); } void UsbGetUserSelectedDevicesFunction::OnDevicesChosen( const std::vector>& devices) { scoped_ptr result(new base::ListValue()); for (const auto& device : devices) { result->Append(PopulateDevice(device.get())); } Respond(OneArgument(result.release())); } UsbRequestAccessFunction::UsbRequestAccessFunction() { } UsbRequestAccessFunction::~UsbRequestAccessFunction() { } ExtensionFunction::ResponseAction UsbRequestAccessFunction::Run() { scoped_ptr parameters = RequestAccess::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); return RespondNow(OneArgument(new base::FundamentalValue(true))); } UsbOpenDeviceFunction::UsbOpenDeviceFunction() { } UsbOpenDeviceFunction::~UsbOpenDeviceFunction() { } ExtensionFunction::ResponseAction UsbOpenDeviceFunction::Run() { scoped_ptr parameters = OpenDevice::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); UsbService* service = device::DeviceClient::Get()->GetUsbService(); if (!service) { return RespondNow(Error(kErrorInitService)); } scoped_refptr device = service->GetDeviceById(parameters->device.device); if (!device.get()) { return RespondNow(Error(kErrorNoDevice)); } if (!HasDevicePermission(device)) { // This function must act as if there is no such device. Otherwise it can be // used to fingerprint unauthorized devices. return RespondNow(Error(kErrorNoDevice)); } device->RequestUsbAccess( -1, /* any interface, unused by the permission broker */ base::Bind(&UsbOpenDeviceFunction::OnRequestAccessComplete, this, device)); return RespondLater(); } void UsbOpenDeviceFunction::OnRequestAccessComplete( scoped_refptr device, bool success) { if (success) { device->Open(base::Bind(&UsbOpenDeviceFunction::OnDeviceOpened, this)); } else { Respond(Error(kErrorPermissionDenied)); } } void UsbOpenDeviceFunction::OnDeviceOpened( scoped_refptr device_handle) { if (!device_handle.get()) { Respond(Error(kErrorOpen)); return; } RecordDeviceLastUsed(); ApiResourceManager* manager = ApiResourceManager::Get(browser_context()); scoped_refptr device = device_handle->GetDevice(); Respond(OneArgument(PopulateConnectionHandle( manager->Add(new UsbDeviceResource(extension_id(), device_handle)), device->vendor_id(), device->product_id()))); } UsbSetConfigurationFunction::UsbSetConfigurationFunction() { } UsbSetConfigurationFunction::~UsbSetConfigurationFunction() { } ExtensionFunction::ResponseAction UsbSetConfigurationFunction::Run() { scoped_ptr parameters = SetConfiguration::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); scoped_refptr device_handle = GetDeviceHandle(parameters->handle); if (!device_handle.get()) { return RespondNow(Error(kErrorNoConnection)); } device_handle->SetConfiguration( parameters->configuration_value, base::Bind(&UsbSetConfigurationFunction::OnComplete, this)); return RespondLater(); } void UsbSetConfigurationFunction::OnComplete(bool success) { if (success) { Respond(NoArguments()); } else { Respond(Error(kErrorCannotSetConfiguration)); } } UsbGetConfigurationFunction::UsbGetConfigurationFunction() { } UsbGetConfigurationFunction::~UsbGetConfigurationFunction() { } ExtensionFunction::ResponseAction UsbGetConfigurationFunction::Run() { scoped_ptr parameters = GetConfiguration::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); scoped_refptr device_handle = GetDeviceHandle(parameters->handle); if (!device_handle.get()) { return RespondNow(Error(kErrorNoConnection)); } const UsbConfigDescriptor* config_descriptor = device_handle->GetDevice()->GetConfiguration(); if (config_descriptor) { ConfigDescriptor config; ConvertConfigDescriptor(*config_descriptor, &config); return RespondNow(OneArgument(config.ToValue().release())); } else { return RespondNow(Error(kErrorNotConfigured)); } } UsbListInterfacesFunction::UsbListInterfacesFunction() { } UsbListInterfacesFunction::~UsbListInterfacesFunction() { } ExtensionFunction::ResponseAction UsbListInterfacesFunction::Run() { scoped_ptr parameters = ListInterfaces::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); scoped_refptr device_handle = GetDeviceHandle(parameters->handle); if (!device_handle.get()) { return RespondNow(Error(kErrorNoConnection)); } const UsbConfigDescriptor* config_descriptor = device_handle->GetDevice()->GetConfiguration(); if (config_descriptor) { ConfigDescriptor config; ConvertConfigDescriptor(*config_descriptor, &config); scoped_ptr result(new base::ListValue); for (size_t i = 0; i < config.interfaces.size(); ++i) { result->Append(config.interfaces[i]->ToValue().release()); } return RespondNow(OneArgument(result.release())); } else { return RespondNow(Error(kErrorNotConfigured)); } } UsbCloseDeviceFunction::UsbCloseDeviceFunction() { } UsbCloseDeviceFunction::~UsbCloseDeviceFunction() { } ExtensionFunction::ResponseAction UsbCloseDeviceFunction::Run() { scoped_ptr parameters = CloseDevice::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); scoped_refptr device_handle = GetDeviceHandle(parameters->handle); if (!device_handle.get()) { return RespondNow(Error(kErrorNoConnection)); } // The device handle is closed when the resource is destroyed. ReleaseDeviceHandle(parameters->handle); return RespondNow(NoArguments()); } UsbClaimInterfaceFunction::UsbClaimInterfaceFunction() { } UsbClaimInterfaceFunction::~UsbClaimInterfaceFunction() { } ExtensionFunction::ResponseAction UsbClaimInterfaceFunction::Run() { scoped_ptr parameters = ClaimInterface::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); scoped_refptr device_handle = GetDeviceHandle(parameters->handle); if (!device_handle.get()) { return RespondNow(Error(kErrorNoConnection)); } device_handle->ClaimInterface( parameters->interface_number, base::Bind(&UsbClaimInterfaceFunction::OnComplete, this)); return RespondLater(); } void UsbClaimInterfaceFunction::OnComplete(bool success) { if (success) { Respond(NoArguments()); } else { Respond(Error(kErrorCannotClaimInterface)); } } UsbReleaseInterfaceFunction::UsbReleaseInterfaceFunction() { } UsbReleaseInterfaceFunction::~UsbReleaseInterfaceFunction() { } ExtensionFunction::ResponseAction UsbReleaseInterfaceFunction::Run() { scoped_ptr parameters = ReleaseInterface::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); scoped_refptr device_handle = GetDeviceHandle(parameters->handle); if (!device_handle.get()) { return RespondNow(Error(kErrorNoConnection)); } if (device_handle->ReleaseInterface(parameters->interface_number)) { return RespondNow(NoArguments()); } else { return RespondNow(Error(kErrorCannotReleaseInterface)); } } UsbSetInterfaceAlternateSettingFunction:: UsbSetInterfaceAlternateSettingFunction() { } UsbSetInterfaceAlternateSettingFunction:: ~UsbSetInterfaceAlternateSettingFunction() { } ExtensionFunction::ResponseAction UsbSetInterfaceAlternateSettingFunction::Run() { scoped_ptr parameters = SetInterfaceAlternateSetting::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); scoped_refptr device_handle = GetDeviceHandle(parameters->handle); if (!device_handle.get()) { return RespondNow(Error(kErrorNoConnection)); } device_handle->SetInterfaceAlternateSetting( parameters->interface_number, parameters->alternate_setting, base::Bind(&UsbSetInterfaceAlternateSettingFunction::OnComplete, this)); return RespondLater(); } void UsbSetInterfaceAlternateSettingFunction::OnComplete(bool success) { if (success) { Respond(NoArguments()); } else { Respond(Error(kErrorCannotSetInterfaceAlternateSetting)); } } UsbControlTransferFunction::UsbControlTransferFunction() { } UsbControlTransferFunction::~UsbControlTransferFunction() { } ExtensionFunction::ResponseAction UsbControlTransferFunction::Run() { scoped_ptr parameters = ControlTransfer::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); scoped_refptr device_handle = GetDeviceHandle(parameters->handle); if (!device_handle.get()) { return RespondNow(Error(kErrorNoConnection)); } const ControlTransferInfo& transfer = parameters->transfer_info; UsbEndpointDirection direction; UsbDeviceHandle::TransferRequestType request_type; UsbDeviceHandle::TransferRecipient recipient; size_t size = 0; if (!ConvertDirectionFromApi(transfer.direction, &direction)) { return RespondNow(Error(kErrorConvertDirection)); } if (!ConvertRequestTypeFromApi(transfer.request_type, &request_type)) { return RespondNow(Error(kErrorConvertRequestType)); } if (!ConvertRecipientFromApi(transfer.recipient, &recipient)) { return RespondNow(Error(kErrorConvertRecipient)); } if (!GetTransferSize(transfer, &size)) { return RespondNow(Error(kErrorInvalidTransferLength)); } scoped_refptr buffer = CreateBufferForTransfer(transfer, direction, size); if (!buffer.get()) { return RespondNow(Error(kErrorMalformedParameters)); } int timeout = transfer.timeout ? *transfer.timeout : 0; if (timeout < 0) { return RespondNow(Error(kErrorInvalidTimeout)); } device_handle->ControlTransfer( direction, request_type, recipient, transfer.request, transfer.value, transfer.index, buffer.get(), size, timeout, base::Bind(&UsbControlTransferFunction::OnCompleted, this)); return RespondLater(); } UsbBulkTransferFunction::UsbBulkTransferFunction() { } UsbBulkTransferFunction::~UsbBulkTransferFunction() { } ExtensionFunction::ResponseAction UsbBulkTransferFunction::Run() { scoped_ptr parameters = BulkTransfer::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); scoped_refptr device_handle = GetDeviceHandle(parameters->handle); if (!device_handle.get()) { return RespondNow(Error(kErrorNoConnection)); } const GenericTransferInfo& transfer = parameters->transfer_info; UsbEndpointDirection direction; size_t size = 0; if (!ConvertDirectionFromApi(transfer.direction, &direction)) { return RespondNow(Error(kErrorConvertDirection)); } if (!GetTransferSize(transfer, &size)) { return RespondNow(Error(kErrorInvalidTransferLength)); } scoped_refptr buffer = CreateBufferForTransfer(transfer, direction, size); if (!buffer.get()) { return RespondNow(Error(kErrorMalformedParameters)); } int timeout = transfer.timeout ? *transfer.timeout : 0; if (timeout < 0) { return RespondNow(Error(kErrorInvalidTimeout)); } device_handle->BulkTransfer( direction, transfer.endpoint, buffer.get(), size, timeout, base::Bind(&UsbBulkTransferFunction::OnCompleted, this)); return RespondLater(); } UsbInterruptTransferFunction::UsbInterruptTransferFunction() { } UsbInterruptTransferFunction::~UsbInterruptTransferFunction() { } ExtensionFunction::ResponseAction UsbInterruptTransferFunction::Run() { scoped_ptr parameters = InterruptTransfer::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); scoped_refptr device_handle = GetDeviceHandle(parameters->handle); if (!device_handle.get()) { return RespondNow(Error(kErrorNoConnection)); } const GenericTransferInfo& transfer = parameters->transfer_info; UsbEndpointDirection direction; size_t size = 0; if (!ConvertDirectionFromApi(transfer.direction, &direction)) { return RespondNow(Error(kErrorConvertDirection)); } if (!GetTransferSize(transfer, &size)) { return RespondNow(Error(kErrorInvalidTransferLength)); } scoped_refptr buffer = CreateBufferForTransfer(transfer, direction, size); if (!buffer.get()) { return RespondNow(Error(kErrorMalformedParameters)); } int timeout = transfer.timeout ? *transfer.timeout : 0; if (timeout < 0) { return RespondNow(Error(kErrorInvalidTimeout)); } device_handle->InterruptTransfer( direction, transfer.endpoint, buffer.get(), size, timeout, base::Bind(&UsbInterruptTransferFunction::OnCompleted, this)); return RespondLater(); } UsbIsochronousTransferFunction::UsbIsochronousTransferFunction() { } UsbIsochronousTransferFunction::~UsbIsochronousTransferFunction() { } ExtensionFunction::ResponseAction UsbIsochronousTransferFunction::Run() { scoped_ptr parameters = IsochronousTransfer::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); scoped_refptr device_handle = GetDeviceHandle(parameters->handle); if (!device_handle.get()) { return RespondNow(Error(kErrorNoConnection)); } const IsochronousTransferInfo& transfer = parameters->transfer_info; const GenericTransferInfo& generic_transfer = transfer.transfer_info; size_t size = 0; UsbEndpointDirection direction; if (!ConvertDirectionFromApi(generic_transfer.direction, &direction)) { return RespondNow(Error(kErrorConvertDirection)); } if (!GetTransferSize(generic_transfer, &size)) { return RespondNow(Error(kErrorInvalidTransferLength)); } if (transfer.packets < 0 || transfer.packets >= kMaxPackets) { return RespondNow(Error(kErrorInvalidNumberOfPackets)); } 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 total_length = packets * packet_length; if (packets > size || total_length > size) { return RespondNow(Error(kErrorTransferLength)); } scoped_refptr buffer = CreateBufferForTransfer(generic_transfer, direction, size); if (!buffer.get()) { return RespondNow(Error(kErrorMalformedParameters)); } int timeout = generic_transfer.timeout ? *generic_transfer.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)); return RespondLater(); } UsbResetDeviceFunction::UsbResetDeviceFunction() { } UsbResetDeviceFunction::~UsbResetDeviceFunction() { } ExtensionFunction::ResponseAction UsbResetDeviceFunction::Run() { parameters_ = ResetDevice::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters_.get()); scoped_refptr device_handle = GetDeviceHandle(parameters_->handle); if (!device_handle.get()) { return RespondNow(Error(kErrorNoConnection)); } device_handle->ResetDevice( base::Bind(&UsbResetDeviceFunction::OnComplete, this)); return RespondLater(); } void UsbResetDeviceFunction::OnComplete(bool success) { if (success) { Respond(OneArgument(new base::FundamentalValue(true))); } else { scoped_refptr device_handle = GetDeviceHandle(parameters_->handle); if (device_handle.get()) { device_handle->Close(); } ReleaseDeviceHandle(parameters_->handle); scoped_ptr error_args(new base::ListValue()); error_args->AppendBoolean(false); // Returning arguments with an error is wrong but we're stuck with it. Respond(ErrorWithArguments(error_args.Pass(), kErrorResetDevice)); } } } // namespace extensions