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