| 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..a06d28421c5451cc626b8af3bc03747838463f11 100644
|
| --- a/device/hid/hid_report_descriptor.cc
|
| +++ b/device/hid/hid_report_descriptor.cc
|
| @@ -8,6 +8,12 @@
|
|
|
| namespace device {
|
|
|
| +namespace {
|
| +
|
| +const int kBitsPerByte = 8;
|
| +
|
| +} // namespace
|
| +
|
| HidReportDescriptor::HidReportDescriptor(const uint8_t* bytes, size_t size) {
|
| size_t header_index = 0;
|
| HidReportDescriptorItem* item = NULL;
|
| @@ -20,42 +26,148 @@ HidReportDescriptor::HidReportDescriptor(const uint8_t* bytes, size_t size) {
|
|
|
| HidReportDescriptor::~HidReportDescriptor() {}
|
|
|
| -void HidReportDescriptor::GetTopLevelCollections(
|
| - std::vector<HidUsageAndPage>* topLevelCollections) {
|
| - DCHECK(topLevelCollections);
|
| - STLClearObject(topLevelCollections);
|
| +void HidReportDescriptor::GetDetails(
|
| + 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()) {
|
| + // 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 += kBitsPerByte;
|
| + if (current_output_report_size > 0)
|
| + current_output_report_size += kBitsPerByte;
|
| + if (current_feature_report_size > 0)
|
| + current_feature_report_size += kBitsPerByte;
|
| +
|
| + // 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 += kBitsPerByte;
|
| + if (current_output_report_size > 0)
|
| + current_output_report_size += kBitsPerByte;
|
| + if (current_feature_report_size > 0)
|
| + current_feature_report_size += kBitsPerByte;
|
| + }
|
| +
|
| + // 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 /= kBitsPerByte;
|
| + *max_output_report_size /= kBitsPerByte;
|
| + *max_feature_report_size /= kBitsPerByte;
|
| }
|
|
|
| } // namespace device
|
|
|