Index: device/hid/hid_report_descriptor_item.cc |
diff --git a/device/hid/hid_report_descriptor_item.cc b/device/hid/hid_report_descriptor_item.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f2ce3b7dd5c0371c81c4359ae6437add2268237e |
--- /dev/null |
+++ b/device/hid/hid_report_descriptor_item.cc |
@@ -0,0 +1,340 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "device/hid/hid_report_descriptor_item.h" |
+ |
+#include <stdlib.h> |
+ |
+#include "base/logging.h" |
+#include "device/hid/hid_usage_and_page.h" |
+ |
+namespace device { |
+ |
+namespace { |
+ |
+std::ostream& operator<<(std::ostream& os, |
+ const HidReportDescriptorItem::Tag& tag) { |
+ switch (tag) { |
+ case HidReportDescriptorItem::kTagDefault: |
+ os << "Default"; |
+ break; |
+ case HidReportDescriptorItem::kTagInput: |
+ os << "Input"; |
+ break; |
+ case HidReportDescriptorItem::kTagOutput: |
+ os << "Output"; |
+ break; |
+ case HidReportDescriptorItem::kTagFeature: |
+ os << "Feature"; |
+ break; |
+ case HidReportDescriptorItem::kTagCollection: |
+ os << "Collection"; |
+ break; |
+ case HidReportDescriptorItem::kTagEndCollection: |
+ os << "End Collection"; |
+ break; |
+ case HidReportDescriptorItem::kTagUsagePage: |
+ os << "Usage Page"; |
+ break; |
+ case HidReportDescriptorItem::kTagLogicalMinimum: |
+ os << "Logical Minimum"; |
+ break; |
+ case HidReportDescriptorItem::kTagLogicalMaximum: |
+ os << "Logical Maximum"; |
+ break; |
+ case HidReportDescriptorItem::kTagPhysicalMinimum: |
+ os << "Physical Minimum"; |
+ break; |
+ case HidReportDescriptorItem::kTagPhysicalMaximum: |
+ os << "Physical Maximum"; |
+ break; |
+ case HidReportDescriptorItem::kTagUnitExponent: |
+ os << "Unit Exponent"; |
+ break; |
+ case HidReportDescriptorItem::kTagUnit: |
+ os << "Unit"; |
+ break; |
+ case HidReportDescriptorItem::kTagReportSize: |
+ os << "Report Size"; |
+ break; |
+ case HidReportDescriptorItem::kTagReportId: |
+ os << "Report ID"; |
+ break; |
+ case HidReportDescriptorItem::kTagReportCount: |
+ os << "Report Count"; |
+ break; |
+ case HidReportDescriptorItem::kTagPush: |
+ os << "Push"; |
+ break; |
+ case HidReportDescriptorItem::kTagPop: |
+ os << "Pop"; |
+ break; |
+ case HidReportDescriptorItem::kTagUsage: |
+ os << "Usage"; |
+ break; |
+ case HidReportDescriptorItem::kTagUsageMinimum: |
+ os << "Usage Minimum"; |
+ break; |
+ case HidReportDescriptorItem::kTagUsageMaximum: |
+ os << "Usage Maximum"; |
+ break; |
+ case HidReportDescriptorItem::kTagDesignatorIndex: |
+ os << "Designator Index"; |
+ break; |
+ case HidReportDescriptorItem::kTagDesignatorMinimum: |
+ os << "Designator Minimum"; |
+ break; |
+ case HidReportDescriptorItem::kTagDesignatorMaximum: |
+ os << "Designator Maximum"; |
+ break; |
+ case HidReportDescriptorItem::kTagStringIndex: |
+ os << "String Index"; |
+ break; |
+ case HidReportDescriptorItem::kTagStringMinimum: |
+ os << "String Minimum"; |
+ break; |
+ case HidReportDescriptorItem::kTagStringMaximum: |
+ os << "String Maximum"; |
+ break; |
+ case HidReportDescriptorItem::kTagDelimiter: |
+ os << "Delimeter"; |
+ break; |
+ case HidReportDescriptorItem::kTagLong: |
+ os << "Long"; |
+ break; |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+ |
+ return os; |
+} |
+ |
+std::ostream& operator<<(std::ostream& os, |
+ const HidReportDescriptorItem::ReportInfo& data) { |
+ if (data.data_or_constant) |
+ os << "Con"; |
+ else |
+ os << "Dat"; |
+ if (data.array_or_variable) |
+ os << "|Arr"; |
+ else |
+ os << "|Var"; |
+ if (data.absolute_or_relative) |
+ os << "|Abs"; |
+ else |
+ os << "|Rel"; |
+ if (data.wrap) |
+ os << "|Wrp"; |
+ else |
+ os << "|NoWrp"; |
+ if (data.linear) |
+ os << "|NoLin"; |
+ else |
+ os << "|Lin"; |
+ if (data.preferred) |
+ os << "|NoPrf"; |
+ else |
+ os << "|Prf"; |
+ if (data.null) |
+ os << "|Null"; |
+ else |
+ os << "|NoNull"; |
+ if (data.bit_field_or_buffer) |
+ os << "|Buff"; |
+ else |
+ os << "|BitF"; |
+ return os; |
+} |
+ |
+std::ostream& operator<<(std::ostream& os, |
+ const HidReportDescriptorItem::CollectionType& type) { |
+ switch (type) { |
+ case HidReportDescriptorItem::kCollectionTypePhysical: |
+ os << "Physical"; |
+ break; |
+ case HidReportDescriptorItem::kCollectionTypeApplication: |
+ os << "Application"; |
+ break; |
+ case HidReportDescriptorItem::kCollectionTypeLogical: |
+ os << "Logical"; |
+ break; |
+ case HidReportDescriptorItem::kCollectionTypeReport: |
+ os << "Report"; |
+ break; |
+ case HidReportDescriptorItem::kCollectionTypeNamedArray: |
+ os << "Named Array"; |
+ break; |
+ case HidReportDescriptorItem::kCollectionTypeUsageSwitch: |
+ os << "Usage Switch"; |
+ break; |
+ case HidReportDescriptorItem::kCollectionTypeUsageModifier: |
+ os << "Usage Modifier"; |
+ break; |
+ case HidReportDescriptorItem::kCollectionTypeReserved: |
+ os << "Reserved"; |
+ break; |
+ case HidReportDescriptorItem::kCollectionTypeVendor: |
+ os << "Vendor"; |
+ break; |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+ return os; |
+} |
+ |
+struct Header { |
+ uint8_t size : 2; |
+ uint8_t type : 2; |
+ uint8_t tag : 4; |
+}; |
+ |
+struct LongHeader { |
+ Header short_header; |
+ uint8_t data_size; |
+ uint8_t long_item_tag; |
+}; |
+ |
+} // namespace |
+ |
+HidReportDescriptorItem::HidReportDescriptorItem( |
+ const uint8_t* bytes, |
+ HidReportDescriptorItem* previous) |
+ : previous_(previous), next_(NULL), parent_(NULL), shortData_(0) { |
+ Header* header = (Header*)&bytes[0]; |
+ tag_ = (Tag)(header->tag << 2 | header->type); |
+ |
+ if (IsLong()) { |
+ LongHeader* long_header = (LongHeader*)&bytes[0]; |
Ken Rockot(use gerrit already)
2014/04/21 21:53:53
Please do not do this. You already have the short
jracle (use Gerrit)
2014/04/23 07:48:32
Sure, it will be equivalent in terms of clarity if
|
+ payload_size_ = long_header->data_size; |
+ } else { |
+ payload_size_ = header->size; |
Ken Rockot(use gerrit already)
2014/04/21 21:53:53
Please verify that payload_size_ <= sizeof(shortDa
jracle (use Gerrit)
2014/04/23 07:48:32
oops, thanks. Don't wanna end-up to another a-la o
|
+ memcpy(&shortData_, &bytes[GetHeaderSize()], payloadSize()); |
+ } |
+ |
+ if (previous) { |
Ken Rockot(use gerrit already)
2014/04/21 21:53:53
Please at least DCHECK(!previous->next_) to clarif
jracle (use Gerrit)
2014/04/23 07:48:32
OK
|
+ previous->next_ = this; |
+ switch (previous->tag()) { |
+ case kTagCollection: |
+ parent_ = previous; |
+ break; |
+ default: |
+ break; |
+ } |
+ if (!parent_) { |
+ switch (tag()) { |
+ case kTagEndCollection: |
+ if (previous->parent()) { |
+ parent_ = previous->parent()->parent(); |
+ } |
+ break; |
+ default: |
+ parent_ = previous->parent(); |
+ break; |
+ } |
+ } |
+ } |
+} |
+ |
+size_t HidReportDescriptorItem::GetDepth() const { |
+ HidReportDescriptorItem* parent_item = parent(); |
+ if (parent_item) |
+ return parent_item->GetDepth() + 1; |
+ return 0; |
+} |
+ |
+bool HidReportDescriptorItem::IsLong() const { return tag() == kTagLong; } |
+ |
+size_t HidReportDescriptorItem::GetHeaderSize() const { |
+ return IsLong() ? 3 : 1; |
+} |
+ |
+size_t HidReportDescriptorItem::GetSize() const { |
+ return GetHeaderSize() + payloadSize(); |
+} |
+ |
+uint32_t HidReportDescriptorItem::GetShortData() const { |
+ DCHECK(!IsLong()); |
+ return shortData_; |
+} |
+ |
+HidReportDescriptorItem::CollectionType |
+HidReportDescriptorItem::GetCollectionTypeFromValue(uint32_t value) { |
+ switch (value) { |
+ case 0x00: |
+ return kCollectionTypePhysical; |
+ case 0x01: |
+ return kCollectionTypePhysical; |
+ case 0x02: |
+ return kCollectionTypePhysical; |
+ case 0x03: |
+ return kCollectionTypePhysical; |
+ case 0x04: |
+ return kCollectionTypePhysical; |
+ case 0x05: |
+ return kCollectionTypePhysical; |
+ case 0x06: |
+ return kCollectionTypePhysical; |
+ default: |
+ break; |
+ } |
+ if (0x80 < value && value < 0xFF) |
+ return kCollectionTypeVendor; |
+ return kCollectionTypeReserved; |
+} |
+ |
+std::ostream& operator<<(std::ostream& os, |
+ const HidReportDescriptorItem& item) { |
+ HidReportDescriptorItem::Tag item_tag = item.tag(); |
+ uint32_t data = item.GetShortData(); |
+ |
+ std::ostringstream sstr; |
+ sstr << item_tag; |
+ sstr << " ("; |
+ |
+ long pos = sstr.tellp(); |
+ switch (item_tag) { |
+ case HidReportDescriptorItem::kTagDefault: |
+ case HidReportDescriptorItem::kTagEndCollection: |
+ case HidReportDescriptorItem::kTagPush: |
+ case HidReportDescriptorItem::kTagPop: |
+ case HidReportDescriptorItem::kTagLong: |
+ break; |
+ |
+ case HidReportDescriptorItem::kTagCollection: |
+ sstr << HidReportDescriptorItem::GetCollectionTypeFromValue(data); |
+ break; |
+ |
+ case HidReportDescriptorItem::kTagInput: |
+ case HidReportDescriptorItem::kTagOutput: |
+ case HidReportDescriptorItem::kTagFeature: |
+ sstr << (HidReportDescriptorItem::ReportInfo&)data; |
+ break; |
+ |
+ case HidReportDescriptorItem::kTagUsagePage: |
+ sstr << (HidUsageAndPage::Page)data; |
+ break; |
+ |
+ case HidReportDescriptorItem::kTagUsage: |
+ case HidReportDescriptorItem::kTagReportId: |
+ sstr << "0x" << std::hex << std::uppercase << data; |
+ break; |
+ |
+ default: |
+ sstr << data; |
+ break; |
+ } |
+ if (pos == sstr.tellp()) { |
+ std::string str = sstr.str(); |
+ str.erase(str.end() - 2, str.end()); |
+ os << str; |
+ } else { |
+ os << sstr.str() << ")"; |
+ } |
+ |
+ return os; |
+} |
+ |
+} // namespace device |