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 "extensions/browser/api/hid/hid_api.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "device/core/device_client.h"
     11 #include "device/hid/hid_connection.h"
     12 #include "device/hid/hid_device_filter.h"
     13 #include "device/hid/hid_device_info.h"
     14 #include "device/hid/hid_service.h"
     15 #include "extensions/browser/api/api_resource_manager.h"
     16 #include "extensions/common/api/hid.h"
     17 #include "net/base/io_buffer.h"
     18 
     19 namespace hid = extensions::core_api::hid;
     20 
     21 using device::HidConnection;
     22 using device::HidDeviceFilter;
     23 using device::HidDeviceInfo;
     24 using device::HidService;
     25 
     26 namespace {
     27 
     28 const char kErrorPermissionDenied[] = "Permission to access device was denied.";
     29 const char kErrorInvalidDeviceId[] = "Invalid HID device ID.";
     30 const char kErrorFailedToOpenDevice[] = "Failed to open HID device.";
     31 const char kErrorConnectionNotFound[] = "Connection not established.";
     32 const char kErrorTransfer[] = "Transfer failed.";
     33 
     34 base::Value* PopulateHidConnection(int connection_id,
     35                                    scoped_refptr<HidConnection> connection) {
     36   hid::HidConnectInfo connection_value;
     37   connection_value.connection_id = connection_id;
     38   return connection_value.ToValue().release();
     39 }
     40 
     41 void ConvertHidDeviceFilter(linked_ptr<hid::DeviceFilter> input,
     42                             HidDeviceFilter* output) {
     43   if (input->vendor_id) {
     44     output->SetVendorId(*input->vendor_id);
     45   }
     46   if (input->product_id) {
     47     output->SetProductId(*input->product_id);
     48   }
     49   if (input->usage_page) {
     50     output->SetUsagePage(*input->usage_page);
     51   }
     52   if (input->usage) {
     53     output->SetUsage(*input->usage);
     54   }
     55 }
     56 
     57 }  // namespace
     58 
     59 namespace extensions {
     60 
     61 HidAsyncApiFunction::HidAsyncApiFunction()
     62     : device_manager_(NULL), connection_manager_(NULL) {}
     63 
     64 HidAsyncApiFunction::~HidAsyncApiFunction() {}
     65 
     66 bool HidAsyncApiFunction::PrePrepare() {
     67 #if defined(OS_MACOSX)
     68   // Migration from FILE thread to UI thread. OS X gets it first.
     69   set_work_thread_id(content::BrowserThread::UI);
     70 #else
     71   // TODO(reillyg): Migrate Linux/CrOS and Windows as well.
     72   set_work_thread_id(content::BrowserThread::FILE);
     73 #endif
     74   device_manager_ = HidDeviceManager::Get(browser_context());
     75   DCHECK(device_manager_);
     76   connection_manager_ =
     77       ApiResourceManager<HidConnectionResource>::Get(browser_context());
     78   DCHECK(connection_manager_);
     79   return true;
     80 }
     81 
     82 bool HidAsyncApiFunction::Respond() { return error_.empty(); }
     83 
     84 HidConnectionResource* HidAsyncApiFunction::GetHidConnectionResource(
     85     int api_resource_id) {
     86   return connection_manager_->Get(extension_->id(), api_resource_id);
     87 }
     88 
     89 void HidAsyncApiFunction::RemoveHidConnectionResource(int api_resource_id) {
     90   connection_manager_->Remove(extension_->id(), api_resource_id);
     91 }
     92 
     93 void HidAsyncApiFunction::CompleteWithError(const std::string& error) {
     94   SetError(error);
     95   AsyncWorkCompleted();
     96 }
     97 
     98 HidGetDevicesFunction::HidGetDevicesFunction() {}
     99 
    100 HidGetDevicesFunction::~HidGetDevicesFunction() {}
    101 
    102 bool HidGetDevicesFunction::Prepare() {
    103   parameters_ = hid::GetDevices::Params::Create(*args_);
    104   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
    105   return true;
    106 }
    107 
    108 void HidGetDevicesFunction::AsyncWorkStart() {
    109   std::vector<HidDeviceFilter> filters;
    110   if (parameters_->options.filters) {
    111     filters.resize(parameters_->options.filters->size());
    112     for (size_t i = 0; i < parameters_->options.filters->size(); ++i) {
    113       ConvertHidDeviceFilter(parameters_->options.filters->at(i), &filters[i]);
    114     }
    115   }
    116   if (parameters_->options.vendor_id) {
    117     HidDeviceFilter legacy_filter;
    118     legacy_filter.SetVendorId(*parameters_->options.vendor_id);
    119     if (parameters_->options.product_id) {
    120       legacy_filter.SetProductId(*parameters_->options.product_id);
    121     }
    122     filters.push_back(legacy_filter);
    123   }
    124 
    125   SetResult(device_manager_->GetApiDevices(extension(), filters).release());
    126   AsyncWorkCompleted();
    127 }
    128 
    129 HidConnectFunction::HidConnectFunction() {}
    130 
    131 HidConnectFunction::~HidConnectFunction() {}
    132 
    133 bool HidConnectFunction::Prepare() {
    134   parameters_ = hid::Connect::Params::Create(*args_);
    135   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
    136   return true;
    137 }
    138 
    139 void HidConnectFunction::AsyncWorkStart() {
    140   device::HidDeviceInfo device_info;
    141   if (!device_manager_->GetDeviceInfo(parameters_->device_id, &device_info)) {
    142     CompleteWithError(kErrorInvalidDeviceId);
    143     return;
    144   }
    145 
    146   if (!device_manager_->HasPermission(extension(), device_info)) {
    147     LOG(WARNING) << "Insufficient permissions to access device.";
    148     CompleteWithError(kErrorPermissionDenied);
    149     return;
    150   }
    151 
    152   HidService* hid_service = device::DeviceClient::Get()->GetHidService();
    153   DCHECK(hid_service);
    154   scoped_refptr<HidConnection> connection =
    155       hid_service->Connect(device_info.device_id);
    156   if (!connection.get()) {
    157     CompleteWithError(kErrorFailedToOpenDevice);
    158     return;
    159   }
    160   int connection_id = connection_manager_->Add(
    161       new HidConnectionResource(extension_->id(), connection));
    162   SetResult(PopulateHidConnection(connection_id, connection));
    163   AsyncWorkCompleted();
    164 }
    165 
    166 HidDisconnectFunction::HidDisconnectFunction() {}
    167 
    168 HidDisconnectFunction::~HidDisconnectFunction() {}
    169 
    170 bool HidDisconnectFunction::Prepare() {
    171   parameters_ = hid::Disconnect::Params::Create(*args_);
    172   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
    173   return true;
    174 }
    175 
    176 void HidDisconnectFunction::AsyncWorkStart() {
    177   int connection_id = parameters_->connection_id;
    178   HidConnectionResource* resource =
    179       connection_manager_->Get(extension_->id(), connection_id);
    180   if (!resource) {
    181     CompleteWithError(kErrorConnectionNotFound);
    182     return;
    183   }
    184   connection_manager_->Remove(extension_->id(), connection_id);
    185   AsyncWorkCompleted();
    186 }
    187 
    188 HidReceiveFunction::HidReceiveFunction() {}
    189 
    190 HidReceiveFunction::~HidReceiveFunction() {}
    191 
    192 bool HidReceiveFunction::Prepare() {
    193   parameters_ = hid::Receive::Params::Create(*args_);
    194   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
    195   return true;
    196 }
    197 
    198 void HidReceiveFunction::AsyncWorkStart() {
    199   int connection_id = parameters_->connection_id;
    200   HidConnectionResource* resource =
    201       connection_manager_->Get(extension_->id(), connection_id);
    202   if (!resource) {
    203     CompleteWithError(kErrorConnectionNotFound);
    204     return;
    205   }
    206 
    207   scoped_refptr<device::HidConnection> connection = resource->connection();
    208   connection->Read(base::Bind(&HidReceiveFunction::OnFinished, this));
    209 }
    210 
    211 void HidReceiveFunction::OnFinished(bool success,
    212                                     scoped_refptr<net::IOBuffer> buffer,
    213                                     size_t size) {
    214   if (!success) {
    215     CompleteWithError(kErrorTransfer);
    216     return;
    217   }
    218 
    219   DCHECK_GE(size, 1u);
    220   int report_id = reinterpret_cast<uint8_t*>(buffer->data())[0];
    221 
    222   scoped_ptr<base::ListValue> result(new base::ListValue());
    223   result->Append(new base::FundamentalValue(report_id));
    224   result->Append(
    225       base::BinaryValue::CreateWithCopiedBuffer(buffer->data() + 1, size - 1));
    226   SetResultList(result.Pass());
    227   AsyncWorkCompleted();
    228 }
    229 
    230 HidSendFunction::HidSendFunction() {}
    231 
    232 HidSendFunction::~HidSendFunction() {}
    233 
    234 bool HidSendFunction::Prepare() {
    235   parameters_ = hid::Send::Params::Create(*args_);
    236   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
    237   return true;
    238 }
    239 
    240 void HidSendFunction::AsyncWorkStart() {
    241   int connection_id = parameters_->connection_id;
    242   HidConnectionResource* resource =
    243       connection_manager_->Get(extension_->id(), connection_id);
    244   if (!resource) {
    245     CompleteWithError(kErrorConnectionNotFound);
    246     return;
    247   }
    248 
    249   scoped_refptr<net::IOBufferWithSize> buffer(
    250       new net::IOBufferWithSize(parameters_->data.size() + 1));
    251   buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id);
    252   memcpy(
    253       buffer->data() + 1, parameters_->data.c_str(), parameters_->data.size());
    254   resource->connection()->Write(
    255       buffer, buffer->size(), base::Bind(&HidSendFunction::OnFinished, this));
    256 }
    257 
    258 void HidSendFunction::OnFinished(bool success) {
    259   if (!success) {
    260     CompleteWithError(kErrorTransfer);
    261     return;
    262   }
    263   AsyncWorkCompleted();
    264 }
    265 
    266 HidReceiveFeatureReportFunction::HidReceiveFeatureReportFunction() {}
    267 
    268 HidReceiveFeatureReportFunction::~HidReceiveFeatureReportFunction() {}
    269 
    270 bool HidReceiveFeatureReportFunction::Prepare() {
    271   parameters_ = hid::ReceiveFeatureReport::Params::Create(*args_);
    272   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
    273   return true;
    274 }
    275 
    276 void HidReceiveFeatureReportFunction::AsyncWorkStart() {
    277   int connection_id = parameters_->connection_id;
    278   HidConnectionResource* resource =
    279       connection_manager_->Get(extension_->id(), connection_id);
    280   if (!resource) {
    281     CompleteWithError(kErrorConnectionNotFound);
    282     return;
    283   }
    284 
    285   scoped_refptr<device::HidConnection> connection = resource->connection();
    286   connection->GetFeatureReport(
    287       static_cast<uint8_t>(parameters_->report_id),
    288       base::Bind(&HidReceiveFeatureReportFunction::OnFinished, this));
    289 }
    290 
    291 void HidReceiveFeatureReportFunction::OnFinished(
    292     bool success,
    293     scoped_refptr<net::IOBuffer> buffer,
    294     size_t size) {
    295   if (!success) {
    296     CompleteWithError(kErrorTransfer);
    297     return;
    298   }
    299 
    300   SetResult(base::BinaryValue::CreateWithCopiedBuffer(buffer->data(), size));
    301   AsyncWorkCompleted();
    302 }
    303 
    304 HidSendFeatureReportFunction::HidSendFeatureReportFunction() {}
    305 
    306 HidSendFeatureReportFunction::~HidSendFeatureReportFunction() {}
    307 
    308 bool HidSendFeatureReportFunction::Prepare() {
    309   parameters_ = hid::SendFeatureReport::Params::Create(*args_);
    310   EXTENSION_FUNCTION_VALIDATE(parameters_.get());
    311   return true;
    312 }
    313 
    314 void HidSendFeatureReportFunction::AsyncWorkStart() {
    315   int connection_id = parameters_->connection_id;
    316   HidConnectionResource* resource =
    317       connection_manager_->Get(extension_->id(), connection_id);
    318   if (!resource) {
    319     CompleteWithError(kErrorConnectionNotFound);
    320     return;
    321   }
    322 
    323   scoped_refptr<net::IOBufferWithSize> buffer(
    324       new net::IOBufferWithSize(parameters_->data.size() + 1));
    325   buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id);
    326   memcpy(
    327       buffer->data() + 1, parameters_->data.c_str(), parameters_->data.size());
    328   resource->connection()->SendFeatureReport(
    329       buffer,
    330       buffer->size(),
    331       base::Bind(&HidSendFeatureReportFunction::OnFinished, this));
    332 }
    333 
    334 void HidSendFeatureReportFunction::OnFinished(bool success) {
    335   if (!success) {
    336     CompleteWithError(kErrorTransfer);
    337     return;
    338   }
    339   AsyncWorkCompleted();
    340 }
    341 
    342 }  // namespace extensions
    343