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 "device/hid/hid_report_descriptor.h"
      6 
      7 #include "base/stl_util.h"
      8 
      9 namespace device {
     10 
     11 namespace {
     12 
     13 const int kBitsPerByte = 8;
     14 
     15 }  // namespace
     16 
     17 HidReportDescriptor::HidReportDescriptor(const uint8_t* bytes, size_t size) {
     18   size_t header_index = 0;
     19   HidReportDescriptorItem* item = NULL;
     20   while (header_index < size) {
     21     item = new HidReportDescriptorItem(&bytes[header_index], item);
     22     items_.push_back(linked_ptr<HidReportDescriptorItem>(item));
     23     header_index += item->GetSize();
     24   }
     25 }
     26 
     27 HidReportDescriptor::~HidReportDescriptor() {}
     28 
     29 void HidReportDescriptor::GetDetails(
     30     std::vector<HidCollectionInfo>* top_level_collections,
     31     bool* has_report_id,
     32     uint16_t* max_input_report_size,
     33     uint16_t* max_output_report_size,
     34     uint16_t* max_feature_report_size) {
     35   DCHECK(top_level_collections);
     36   DCHECK(max_input_report_size);
     37   DCHECK(max_output_report_size);
     38   DCHECK(max_feature_report_size);
     39   STLClearObject(top_level_collections);
     40 
     41   *has_report_id = false;
     42   *max_input_report_size = 0;
     43   *max_output_report_size = 0;
     44   *max_feature_report_size = 0;
     45 
     46   // Global tags data:
     47   HidUsageAndPage::Page current_usage_page = HidUsageAndPage::kPageUndefined;
     48   uint16_t current_report_count = 0;
     49   uint16_t cached_report_count = 0;
     50   uint16_t current_report_size = 0;
     51   uint16_t cached_report_size = 0;
     52   uint16_t current_input_report_size = 0;
     53   uint16_t current_output_report_size = 0;
     54   uint16_t current_feature_report_size = 0;
     55 
     56   // Local tags data:
     57   uint16_t current_usage = 0;
     58 
     59   for (std::vector<linked_ptr<HidReportDescriptorItem> >::const_iterator
     60            items_iter = items().begin();
     61        items_iter != items().end();
     62        ++items_iter) {
     63     linked_ptr<HidReportDescriptorItem> current_item = *items_iter;
     64 
     65     switch (current_item->tag()) {
     66       // Main tags:
     67       case HidReportDescriptorItem::kTagCollection:
     68         if (!current_item->parent()) {
     69           // This is a top-level collection.
     70           HidCollectionInfo collection;
     71           collection.usage = HidUsageAndPage(current_usage, current_usage_page);
     72           top_level_collections->push_back(collection);
     73         }
     74         break;
     75       case HidReportDescriptorItem::kTagInput:
     76         current_input_report_size += current_report_count * current_report_size;
     77         break;
     78       case HidReportDescriptorItem::kTagOutput:
     79         current_output_report_size +=
     80             current_report_count * current_report_size;
     81         break;
     82       case HidReportDescriptorItem::kTagFeature:
     83         current_feature_report_size +=
     84             current_report_count * current_report_size;
     85         break;
     86 
     87       // Global tags:
     88       case HidReportDescriptorItem::kTagUsagePage:
     89         current_usage_page =
     90             (HidUsageAndPage::Page)current_item->GetShortData();
     91         break;
     92       case HidReportDescriptorItem::kTagReportId:
     93         if (top_level_collections->size() > 0) {
     94           // Store report ID.
     95           top_level_collections->back().report_ids.insert(
     96               current_item->GetShortData());
     97           *has_report_id = true;
     98 
     99           // Update max report sizes.
    100           *max_input_report_size =
    101               std::max(*max_input_report_size, current_input_report_size);
    102           *max_output_report_size =
    103               std::max(*max_output_report_size, current_output_report_size);
    104           *max_feature_report_size =
    105               std::max(*max_feature_report_size, current_feature_report_size);
    106 
    107           // Reset the report sizes for the next report ID.
    108           current_input_report_size = 0;
    109           current_output_report_size = 0;
    110           current_feature_report_size = 0;
    111         }
    112         break;
    113       case HidReportDescriptorItem::kTagReportCount:
    114         current_report_count = current_item->GetShortData();
    115         break;
    116       case HidReportDescriptorItem::kTagReportSize:
    117         current_report_size = current_item->GetShortData();
    118         break;
    119       case HidReportDescriptorItem::kTagPush:
    120         // Cache report count and size.
    121         cached_report_count = current_report_count;
    122         cached_report_size = current_report_size;
    123         break;
    124       case HidReportDescriptorItem::kTagPop:
    125         // Restore cache.
    126         current_report_count = cached_report_count;
    127         current_report_size = cached_report_size;
    128         // Reset cache.
    129         cached_report_count = 0;
    130         cached_report_size = 0;
    131         break;
    132 
    133       // Local tags:
    134       case HidReportDescriptorItem::kTagUsage:
    135         current_usage = current_item->GetShortData();
    136         break;
    137 
    138       default:
    139         break;
    140     }
    141   }
    142 
    143   // Update max report sizes
    144   *max_input_report_size =
    145       std::max(*max_input_report_size, current_input_report_size);
    146   *max_output_report_size =
    147       std::max(*max_output_report_size, current_output_report_size);
    148   *max_feature_report_size =
    149       std::max(*max_feature_report_size, current_feature_report_size);
    150 
    151   // Convert bits into bytes
    152   *max_input_report_size /= kBitsPerByte;
    153   *max_output_report_size /= kBitsPerByte;
    154   *max_feature_report_size /= kBitsPerByte;
    155 }
    156 
    157 }  // namespace device
    158