Home | History | Annotate | Download | only in hid
      1 // Copyright (c) 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 "device/hid/hid_connection.h"
      6 
      7 #include <algorithm>
      8 
      9 namespace device {
     10 
     11 namespace {
     12 
     13 // Functor used to filter collections by report ID.
     14 struct CollectionHasReportId {
     15   explicit CollectionHasReportId(uint8_t report_id) : report_id_(report_id) {}
     16 
     17   bool operator()(const HidCollectionInfo& info) const {
     18     if (info.report_ids.size() == 0 ||
     19         report_id_ == HidConnection::kNullReportId)
     20       return false;
     21 
     22     if (report_id_ == HidConnection::kAnyReportId)
     23       return true;
     24 
     25     return std::find(info.report_ids.begin(),
     26                      info.report_ids.end(),
     27                      report_id_) != info.report_ids.end();
     28   }
     29 
     30  private:
     31   const uint8_t report_id_;
     32 };
     33 
     34 // Functor returning true if collection has a protected usage.
     35 struct CollectionIsProtected {
     36   bool operator()(const HidCollectionInfo& info) const {
     37     return info.usage.IsProtected();
     38   }
     39 };
     40 
     41 bool FindCollectionByReportId(const HidDeviceInfo& device_info,
     42                               uint8_t report_id,
     43                               HidCollectionInfo* collection_info) {
     44   std::vector<HidCollectionInfo>::const_iterator collection_iter =
     45       std::find_if(device_info.collections.begin(),
     46                    device_info.collections.end(),
     47                    CollectionHasReportId(report_id));
     48   if (collection_iter != device_info.collections.end()) {
     49     if (collection_info) {
     50       *collection_info = *collection_iter;
     51     }
     52     return true;
     53   }
     54 
     55   return false;
     56 }
     57 
     58 bool HasProtectedCollection(const HidDeviceInfo& device_info) {
     59   return std::find_if(device_info.collections.begin(),
     60                       device_info.collections.end(),
     61                       CollectionIsProtected()) != device_info.collections.end();
     62 }
     63 
     64 }  // namespace
     65 
     66 HidConnection::HidConnection(const HidDeviceInfo& device_info)
     67     : device_info_(device_info), closed_(false) {
     68   has_protected_collection_ = HasProtectedCollection(device_info);
     69 }
     70 
     71 HidConnection::~HidConnection() {
     72   DCHECK(thread_checker_.CalledOnValidThread());
     73   DCHECK(closed_);
     74 }
     75 
     76 void HidConnection::Close() {
     77   DCHECK(thread_checker_.CalledOnValidThread());
     78   DCHECK(!closed_);
     79 
     80   PlatformClose();
     81   closed_ = true;
     82 }
     83 
     84 void HidConnection::Read(const ReadCallback& callback) {
     85   DCHECK(thread_checker_.CalledOnValidThread());
     86   if (device_info_.max_input_report_size == 0) {
     87     VLOG(1) << "This device does not support input reports.";
     88     callback.Run(false, NULL, 0);
     89     return;
     90   }
     91 
     92   PlatformRead(callback);
     93 }
     94 
     95 void HidConnection::Write(scoped_refptr<net::IOBuffer> buffer,
     96                           size_t size,
     97                           const WriteCallback& callback) {
     98   DCHECK(thread_checker_.CalledOnValidThread());
     99   if (device_info_.max_output_report_size == 0) {
    100     VLOG(1) << "This device does not support output reports.";
    101     callback.Run(false);
    102     return;
    103   }
    104   DCHECK_GE(size, 1u);
    105   uint8_t report_id = buffer->data()[0];
    106   if (device_info().has_report_id != (report_id != 0)) {
    107     VLOG(1) << "Invalid output report ID.";
    108     callback.Run(false);
    109     return;
    110   }
    111   if (IsReportIdProtected(report_id)) {
    112     VLOG(1) << "Attempt to set a protected output report.";
    113     callback.Run(false);
    114     return;
    115   }
    116 
    117   PlatformWrite(buffer, size, callback);
    118 }
    119 
    120 void HidConnection::GetFeatureReport(uint8_t report_id,
    121                                      const ReadCallback& callback) {
    122   DCHECK(thread_checker_.CalledOnValidThread());
    123   if (device_info_.max_feature_report_size == 0) {
    124     VLOG(1) << "This device does not support feature reports.";
    125     callback.Run(false, NULL, 0);
    126     return;
    127   }
    128   if (device_info().has_report_id != (report_id != 0)) {
    129     VLOG(1) << "Invalid feature report ID.";
    130     callback.Run(false, NULL, 0);
    131     return;
    132   }
    133   if (IsReportIdProtected(report_id)) {
    134     VLOG(1) << "Attempt to get a protected feature report.";
    135     callback.Run(false, NULL, 0);
    136     return;
    137   }
    138 
    139   PlatformGetFeatureReport(report_id, callback);
    140 }
    141 
    142 void HidConnection::SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
    143                                       size_t size,
    144                                       const WriteCallback& callback) {
    145   DCHECK(thread_checker_.CalledOnValidThread());
    146   if (device_info_.max_feature_report_size == 0) {
    147     VLOG(1) << "This device does not support feature reports.";
    148     callback.Run(false);
    149     return;
    150   }
    151   DCHECK_GE(size, 1u);
    152   uint8_t report_id = buffer->data()[0];
    153   if (device_info().has_report_id != (report_id != 0)) {
    154     VLOG(1) << "Invalid feature report ID.";
    155     callback.Run(false);
    156     return;
    157   }
    158   if (IsReportIdProtected(report_id)) {
    159     VLOG(1) << "Attempt to set a protected feature report.";
    160     callback.Run(false);
    161     return;
    162   }
    163 
    164   PlatformSendFeatureReport(buffer, size, callback);
    165 }
    166 
    167 bool HidConnection::CompleteRead(scoped_refptr<net::IOBuffer> buffer,
    168                                  size_t size,
    169                                  const ReadCallback& callback) {
    170   DCHECK_GE(size, 1u);
    171   uint8_t report_id = buffer->data()[0];
    172   if (IsReportIdProtected(report_id)) {
    173     VLOG(1) << "Filtered a protected input report.";
    174     return false;
    175   }
    176 
    177   callback.Run(true, buffer, size);
    178   return true;
    179 }
    180 
    181 bool HidConnection::IsReportIdProtected(uint8_t report_id) {
    182   HidCollectionInfo collection_info;
    183   if (FindCollectionByReportId(device_info_, report_id, &collection_info)) {
    184     return collection_info.usage.IsProtected();
    185   }
    186 
    187   return has_protected_collection();
    188 }
    189 
    190 PendingHidReport::PendingHidReport() {}
    191 
    192 PendingHidReport::~PendingHidReport() {}
    193 
    194 PendingHidRead::PendingHidRead() {}
    195 
    196 PendingHidRead::~PendingHidRead() {}
    197 
    198 }  // namespace device
    199