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