Home | History | Annotate | Download | only in hid
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/extensions/api/hid/hid_api.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "chrome/common/extensions/api/hid.h"
     11 #include "device/hid/hid_connection.h"
     12 #include "device/hid/hid_device_info.h"
     13 #include "device/hid/hid_service.h"
     14 #include "extensions/browser/api/api_resource_manager.h"
     15 #include "extensions/common/permissions/permissions_data.h"
     16 #include "extensions/common/permissions/usb_device_permission.h"
     17 #include "net/base/io_buffer.h"
     18 
     19 namespace hid = extensions::api::hid;
     20 
     21 using device::HidConnection;
     22 using device::HidDeviceInfo;
     23 using device::HidService;
     24 
     25 namespace {
     26 
     27 const char kErrorPermissionDenied[] = "Permission to access device was denied.";
     28 const char kErrorInvalidDeviceId[] = "Invalid HID device ID.";
     29 const char kErrorFailedToOpenDevice[] = "Failed to open HID device.";
     30 const char kErrorConnectionNotFound[] = "Connection not established.";
     31 const char kErrorTransfer[] = "Transfer failed.";
     32 
     33 base::Value* PopulateHidConnection(int connection_id,
     34                                    scoped_refptr<HidConnection> connection) {
     35   hid::HidConnectInfo connection_value;
     36   connection_value.connection_id = connection_id;
     37   return connection_value.ToValue().release();
     38 }
     39 
     40 }  // namespace
     41 
     42 namespace extensions {
     43 
     44 HidAsyncApiFunction::HidAsyncApiFunction()
     45     : device_manager_(NULL), connection_manager_(NULL) {}
     46 
     47 HidAsyncApiFunction::~HidAsyncApiFunction() {}
     48 
     49 bool HidAsyncApiFunction::PrePrepare() {
     50   device_manager_ = HidDeviceManager::Get(browser_context());
     51   DCHECK(device_manager_);
     52   connection_manager_ =
     53       ApiResourceManager<HidConnectionResource>::Get(browser_context());
     54   DCHECK(connection_manager_);
     55   set_work_thread_id(content::BrowserThread::FILE);
     56   return true;
     57 }
     58 
     59 bool HidAsyncApiFunction::Respond() { return error_.empty(); }
     60 
     61 HidConnectionResource* HidAsyncApiFunction::GetHidConnectionResource(
     62     int api_resource_id) {
     63   return connection_manager_->Get(extension_->id(), api_resource_id);
     64 }
     65 
     66 void HidAsyncApiFunction::RemoveHidConnectionResource(int api_resource_id) {
     67   connection_manager_->Remove(extension_->id(), api_resource_id);
     68 }
     69 
     70 void HidAsyncApiFunction::CompleteWithError(const std::string& error) {
     71   SetError(error);
     72   AsyncWorkCompleted();
     73 }
     74 
     75 HidGetDevicesFunction::HidGetDevicesFunction() {}
     76 
     77 HidGetDevicesFunction::~HidGetDevicesFunction() {}
     78 
     79 bool HidGetDevicesFunction::Prepare() {
     80   parameters_ = hid::GetDevices::Params::Create(*args_);
     81   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
     82   return true;
     83 }
     84 
     85 void HidGetDevicesFunction::AsyncWorkStart() {
     86   const uint16_t vendor_id = parameters_->options.vendor_id;
     87   const uint16_t product_id = parameters_->options.product_id;
     88   UsbDevicePermission::CheckParam param(
     89       vendor_id, product_id, UsbDevicePermissionData::UNSPECIFIED_INTERFACE);
     90   if (!GetExtension()->permissions_data()->CheckAPIPermissionWithParam(
     91           APIPermission::kUsbDevice, &param)) {
     92     LOG(WARNING) << "Insufficient permissions to access device.";
     93     CompleteWithError(kErrorPermissionDenied);
     94     return;
     95   }
     96 
     97   SetResult(device_manager_->GetApiDevices(vendor_id, product_id).release());
     98   AsyncWorkCompleted();
     99 }
    100 
    101 HidConnectFunction::HidConnectFunction() {}
    102 
    103 HidConnectFunction::~HidConnectFunction() {}
    104 
    105 bool HidConnectFunction::Prepare() {
    106   parameters_ = hid::Connect::Params::Create(*args_);
    107   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
    108   return true;
    109 }
    110 
    111 void HidConnectFunction::AsyncWorkStart() {
    112   device::HidDeviceInfo device_info;
    113   if (!device_manager_->GetDeviceInfo(parameters_->device_id, &device_info)) {
    114     CompleteWithError(kErrorInvalidDeviceId);
    115     return;
    116   }
    117 
    118   UsbDevicePermission::CheckParam param(
    119       device_info.vendor_id,
    120       device_info.product_id,
    121       UsbDevicePermissionData::UNSPECIFIED_INTERFACE);
    122   if (!GetExtension()->permissions_data()->CheckAPIPermissionWithParam(
    123           APIPermission::kUsbDevice, &param)) {
    124     LOG(WARNING) << "Insufficient permissions to access device.";
    125     CompleteWithError(kErrorPermissionDenied);
    126     return;
    127   }
    128 
    129   HidService* hid_service = HidService::GetInstance();
    130   DCHECK(hid_service);
    131   scoped_refptr<HidConnection> connection =
    132       hid_service->Connect(device_info.device_id);
    133   if (!connection) {
    134     CompleteWithError(kErrorFailedToOpenDevice);
    135     return;
    136   }
    137   int connection_id = connection_manager_->Add(
    138       new HidConnectionResource(extension_->id(), connection));
    139   SetResult(PopulateHidConnection(connection_id, connection));
    140   AsyncWorkCompleted();
    141 }
    142 
    143 HidDisconnectFunction::HidDisconnectFunction() {}
    144 
    145 HidDisconnectFunction::~HidDisconnectFunction() {}
    146 
    147 bool HidDisconnectFunction::Prepare() {
    148   parameters_ = hid::Disconnect::Params::Create(*args_);
    149   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
    150   return true;
    151 }
    152 
    153 void HidDisconnectFunction::AsyncWorkStart() {
    154   int connection_id = parameters_->connection_id;
    155   HidConnectionResource* resource =
    156       connection_manager_->Get(extension_->id(), connection_id);
    157   if (!resource) {
    158     CompleteWithError(kErrorConnectionNotFound);
    159     return;
    160   }
    161   connection_manager_->Remove(extension_->id(), connection_id);
    162   AsyncWorkCompleted();
    163 }
    164 
    165 HidReceiveFunction::HidReceiveFunction() {}
    166 
    167 HidReceiveFunction::~HidReceiveFunction() {}
    168 
    169 bool HidReceiveFunction::Prepare() {
    170   parameters_ = hid::Receive::Params::Create(*args_);
    171   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
    172   return true;
    173 }
    174 
    175 void HidReceiveFunction::AsyncWorkStart() {
    176   int connection_id = parameters_->connection_id;
    177   HidConnectionResource* resource =
    178       connection_manager_->Get(extension_->id(), connection_id);
    179   if (!resource) {
    180     CompleteWithError(kErrorConnectionNotFound);
    181     return;
    182   }
    183 
    184   buffer_ = new net::IOBufferWithSize(parameters_->size);
    185   resource->connection()->Read(
    186       buffer_, base::Bind(&HidReceiveFunction::OnFinished, this));
    187 }
    188 
    189 void HidReceiveFunction::OnFinished(bool success, size_t bytes) {
    190   if (!success) {
    191     CompleteWithError(kErrorTransfer);
    192     return;
    193   }
    194 
    195   SetResult(base::BinaryValue::CreateWithCopiedBuffer(buffer_->data(), bytes));
    196   AsyncWorkCompleted();
    197 }
    198 
    199 HidSendFunction::HidSendFunction() {}
    200 
    201 HidSendFunction::~HidSendFunction() {}
    202 
    203 bool HidSendFunction::Prepare() {
    204   parameters_ = hid::Send::Params::Create(*args_);
    205   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
    206   return true;
    207 }
    208 
    209 void HidSendFunction::AsyncWorkStart() {
    210   int connection_id = parameters_->connection_id;
    211   HidConnectionResource* resource =
    212       connection_manager_->Get(extension_->id(), connection_id);
    213   if (!resource) {
    214     CompleteWithError(kErrorConnectionNotFound);
    215     return;
    216   }
    217 
    218   scoped_refptr<net::IOBufferWithSize> buffer(
    219       new net::IOBufferWithSize(parameters_->data.size()));
    220   memcpy(buffer->data(), parameters_->data.c_str(), parameters_->data.size());
    221   resource->connection()->Write(static_cast<uint8_t>(parameters_->report_id),
    222                                 buffer,
    223                                 base::Bind(&HidSendFunction::OnFinished, this));
    224 }
    225 
    226 void HidSendFunction::OnFinished(bool success, size_t bytes) {
    227   if (!success) {
    228     CompleteWithError(kErrorTransfer);
    229     return;
    230   }
    231   AsyncWorkCompleted();
    232 }
    233 
    234 HidReceiveFeatureReportFunction::HidReceiveFeatureReportFunction() {}
    235 
    236 HidReceiveFeatureReportFunction::~HidReceiveFeatureReportFunction() {}
    237 
    238 bool HidReceiveFeatureReportFunction::Prepare() {
    239   parameters_ = hid::ReceiveFeatureReport::Params::Create(*args_);
    240   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
    241   return true;
    242 }
    243 
    244 void HidReceiveFeatureReportFunction::AsyncWorkStart() {
    245   int connection_id = parameters_->connection_id;
    246   HidConnectionResource* resource =
    247       connection_manager_->Get(extension_->id(), connection_id);
    248   if (!resource) {
    249     CompleteWithError(kErrorConnectionNotFound);
    250     return;
    251   }
    252   buffer_ = new net::IOBufferWithSize(parameters_->size);
    253   resource->connection()->GetFeatureReport(
    254       static_cast<uint8_t>(parameters_->report_id),
    255       buffer_,
    256       base::Bind(&HidReceiveFeatureReportFunction::OnFinished, this));
    257 }
    258 
    259 void HidReceiveFeatureReportFunction::OnFinished(bool success, size_t bytes) {
    260   if (!success) {
    261     CompleteWithError(kErrorTransfer);
    262     return;
    263   }
    264 
    265   SetResult(base::BinaryValue::CreateWithCopiedBuffer(buffer_->data(), bytes));
    266   AsyncWorkCompleted();
    267 }
    268 
    269 HidSendFeatureReportFunction::HidSendFeatureReportFunction() {}
    270 
    271 HidSendFeatureReportFunction::~HidSendFeatureReportFunction() {}
    272 
    273 bool HidSendFeatureReportFunction::Prepare() {
    274   parameters_ = hid::SendFeatureReport::Params::Create(*args_);
    275   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
    276   return true;
    277 }
    278 
    279 void HidSendFeatureReportFunction::AsyncWorkStart() {
    280   int connection_id = parameters_->connection_id;
    281   HidConnectionResource* resource =
    282       connection_manager_->Get(extension_->id(), connection_id);
    283   if (!resource) {
    284     CompleteWithError(kErrorConnectionNotFound);
    285     return;
    286   }
    287   scoped_refptr<net::IOBufferWithSize> buffer(
    288       new net::IOBufferWithSize(parameters_->data.size()));
    289   resource->connection()->SendFeatureReport(
    290       static_cast<uint8_t>(parameters_->report_id),
    291       buffer,
    292       base::Bind(&HidSendFeatureReportFunction::OnFinished, this));
    293 }
    294 
    295 void HidSendFeatureReportFunction::OnFinished(bool success, size_t bytes) {
    296   if (!success) {
    297     CompleteWithError(kErrorTransfer);
    298     return;
    299   }
    300   AsyncWorkCompleted();
    301 }
    302 
    303 }  // namespace extensions
    304