Index: device/hid/hid_report_descriptor.cc |
diff --git a/device/hid/hid_report_descriptor.cc b/device/hid/hid_report_descriptor.cc |
index f2cb0f4901f10419b16079c372e2391d7d4bd40b..00e16cf5aeed29e4cee030ffcd477020addbb03f 100644 |
--- a/device/hid/hid_report_descriptor.cc |
+++ b/device/hid/hid_report_descriptor.cc |
@@ -8,6 +8,12 @@ |
namespace device { |
+namespace { |
+ |
+const int kOneByte = 8; |
Ken Rockot(use gerrit already)
2014/06/06 20:04:43
How about "kBitsPerByte"
jracle (use Gerrit)
2014/06/07 12:56:21
+2!
On 2014/06/06 20:04:43, Ken Rockot wrote:
|
+ |
+} // namespace |
+ |
HidReportDescriptor::HidReportDescriptor(const uint8_t* bytes, size_t size) { |
size_t header_index = 0; |
HidReportDescriptorItem* item = NULL; |
@@ -21,41 +27,147 @@ HidReportDescriptor::HidReportDescriptor(const uint8_t* bytes, size_t size) { |
HidReportDescriptor::~HidReportDescriptor() {} |
void HidReportDescriptor::GetTopLevelCollections( |
- std::vector<HidUsageAndPage>* topLevelCollections) { |
- DCHECK(topLevelCollections); |
- STLClearObject(topLevelCollections); |
+ std::vector<HidCollectionInfo>* top_level_collections, |
+ int* max_input_report_size, |
+ int* max_output_report_size, |
+ int* max_feature_report_size) { |
+ DCHECK(top_level_collections); |
+ DCHECK(max_input_report_size); |
+ DCHECK(max_output_report_size); |
+ DCHECK(max_feature_report_size); |
+ STLClearObject(top_level_collections); |
+ |
+ *max_input_report_size = 0; |
+ *max_output_report_size = 0; |
+ *max_feature_report_size = 0; |
+ |
+ // Global tags data: |
+ HidUsageAndPage::Page current_usage_page = HidUsageAndPage::kPageUndefined; |
+ int current_report_count = 0; |
+ int cached_report_count = 0; |
+ int current_report_size = 0; |
+ int cached_report_size = 0; |
+ int current_input_report_size = 0; |
+ int current_output_report_size = 0; |
+ int current_feature_report_size = 0; |
+ |
+ // Local tags data: |
+ uint16_t current_usage = 0; |
for (std::vector<linked_ptr<HidReportDescriptorItem> >::const_iterator |
items_iter = items().begin(); |
items_iter != items().end(); |
++items_iter) { |
- linked_ptr<HidReportDescriptorItem> item = *items_iter; |
- |
- bool isTopLevelCollection = |
- item->tag() == HidReportDescriptorItem::kTagCollection && |
- item->parent() == NULL; |
- |
- if (isTopLevelCollection) { |
- uint16_t collection_usage = 0; |
- HidUsageAndPage::Page collection_usage_page = |
- HidUsageAndPage::kPageUndefined; |
- |
- HidReportDescriptorItem* usage = item->previous(); |
- if (usage && usage->tag() == HidReportDescriptorItem::kTagUsage) { |
- collection_usage = usage->GetShortData(); |
- } |
- |
- HidReportDescriptorItem* usage_page = usage->previous(); |
- if (usage_page && |
- usage_page->tag() == HidReportDescriptorItem::kTagUsagePage) { |
- collection_usage_page = |
- (HidUsageAndPage::Page)usage_page->GetShortData(); |
- } |
- |
- topLevelCollections->push_back( |
- HidUsageAndPage(collection_usage, collection_usage_page)); |
+ linked_ptr<HidReportDescriptorItem> current_item = *items_iter; |
+ |
+ switch (current_item->tag()) { |
Ken Rockot(use gerrit already)
2014/06/06 20:04:43
In general this is awesome. I wish it were a littl
jracle (use Gerrit)
2014/06/07 12:56:21
Thanks, I'm also a bit uncomfortable with it, but
|
+ // Main tags: |
+ case HidReportDescriptorItem::kTagCollection: |
+ if (!current_item->parent()) { |
+ // This is a top-level collection. |
+ HidCollectionInfo collection; |
+ collection.usage = HidUsageAndPage(current_usage, current_usage_page); |
+ top_level_collections->push_back(collection); |
+ } |
+ break; |
+ case HidReportDescriptorItem::kTagInput: |
+ current_input_report_size += current_report_count * current_report_size; |
+ break; |
+ case HidReportDescriptorItem::kTagOutput: |
+ current_output_report_size += |
+ current_report_count * current_report_size; |
+ break; |
+ case HidReportDescriptorItem::kTagFeature: |
+ current_feature_report_size += |
+ current_report_count * current_report_size; |
+ break; |
+ |
+ // Global tags: |
+ case HidReportDescriptorItem::kTagUsagePage: |
+ current_usage_page = |
+ (HidUsageAndPage::Page)current_item->GetShortData(); |
+ break; |
+ case HidReportDescriptorItem::kTagReportId: |
+ if (top_level_collections->size() > 0) { |
+ // Store report ID. |
+ top_level_collections->back().report_ids.insert( |
+ current_item->GetShortData()); |
+ |
+ // We need to increase report sizes by report ID field length. |
+ if (current_input_report_size > 0) |
+ current_input_report_size += kOneByte; |
+ if (current_output_report_size > 0) |
+ current_output_report_size += kOneByte; |
+ if (current_feature_report_size > 0) |
+ current_feature_report_size += kOneByte; |
+ |
+ // Update max report sizes. |
+ *max_input_report_size = |
+ std::max(*max_input_report_size, current_input_report_size); |
+ *max_output_report_size = |
+ std::max(*max_output_report_size, current_output_report_size); |
+ *max_feature_report_size = |
+ std::max(*max_feature_report_size, current_feature_report_size); |
+ |
+ // Set report sizes to be 1-byte long (report ID field). |
+ current_input_report_size = 0; |
+ current_output_report_size = 0; |
+ current_feature_report_size = 0; |
+ } |
+ break; |
+ case HidReportDescriptorItem::kTagReportCount: |
+ current_report_count = current_item->GetShortData(); |
+ break; |
+ case HidReportDescriptorItem::kTagReportSize: |
+ current_report_size = current_item->GetShortData(); |
+ break; |
+ case HidReportDescriptorItem::kTagPush: |
+ // Cache report count and size. |
+ cached_report_count = current_report_count; |
+ cached_report_size = current_report_size; |
+ break; |
+ case HidReportDescriptorItem::kTagPop: |
+ // Restore cache. |
+ current_report_count = cached_report_count; |
+ current_report_size = cached_report_size; |
+ // Reset cache. |
+ cached_report_count = 0; |
+ cached_report_size = 0; |
+ break; |
+ |
+ // Local tags: |
+ case HidReportDescriptorItem::kTagUsage: |
+ current_usage = current_item->GetShortData(); |
+ break; |
+ |
+ default: |
+ break; |
} |
} |
+ |
+ if (top_level_collections->size() > 0 && |
+ top_level_collections->back().report_ids.size() > 0) { |
+ // We need to increase report sizes by report ID field length. |
+ if (current_input_report_size > 0) |
+ current_input_report_size += kOneByte; |
+ if (current_output_report_size > 0) |
+ current_output_report_size += kOneByte; |
+ if (current_feature_report_size > 0) |
+ current_feature_report_size += kOneByte; |
+ } |
+ |
+ // Update max report sizes |
+ *max_input_report_size = |
+ std::max(*max_input_report_size, current_input_report_size); |
+ *max_output_report_size = |
+ std::max(*max_output_report_size, current_output_report_size); |
+ *max_feature_report_size = |
+ std::max(*max_feature_report_size, current_feature_report_size); |
+ |
+ // Convert bits into bytes |
+ *max_input_report_size /= kOneByte; |
+ *max_output_report_size /= kOneByte; |
+ *max_feature_report_size /= kOneByte; |
} |
} // namespace device |