Commit c9e45be2 authored by Matt Reynolds's avatar Matt Reynolds Committed by Commit Bot

Add mojo types for HID report descriptors

Information about the HID report descriptor, including a hierarchical
representation of the described collections and reports, will be made
available through the WebHID API. This CL adds information about input,
output, and feature reports contained within a collection, as well as a
list of the children of the collection.

BUG=890096

Change-Id: I7d40fef222baf9456dda0920ee88550ca02ff41f
Reviewed-on: https://chromium-review.googlesource.com/c/1381263
Commit-Queue: Matt Reynolds <mattreynolds@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarOvidio de Jesús Ruiz-Henríquez <odejesush@chromium.org>
Cr-Commit-Position: refs/heads/master@{#636632}
parent 2b9a5b21
......@@ -57,7 +57,9 @@ void PopulateHidDeviceInfo(hid::HidDeviceInfo* output,
api_collection.usage_page = collection->usage->usage_page;
api_collection.usage = collection->usage->usage;
api_collection.report_ids = collection->report_ids;
api_collection.report_ids.insert(api_collection.report_ids.begin(),
collection->report_ids.begin(),
collection->report_ids.end());
output->collections.push_back(std::move(api_collection));
}
......
......@@ -204,10 +204,9 @@ void HidCollection::AddReportItem(HidReportDescriptorItem::Tag tag,
report->push_back(HidReportItem::Create(tag, report_info, state));
}
mojom::HidCollectionInfoPtr HidCollection::GetDetails(
size_t* max_input_report_bits,
size_t* max_output_report_bits,
size_t* max_feature_report_bits) {
void HidCollection::GetMaxReportSizes(size_t* max_input_report_bits,
size_t* max_output_report_bits,
size_t* max_feature_report_bits) const {
DCHECK(max_input_report_bits);
DCHECK(max_output_report_bits);
DCHECK(max_feature_report_bits);
......@@ -253,7 +252,39 @@ mojom::HidCollectionInfoPtr HidCollection::GetDetails(
std::max(entry.max_report_bits, size_t{report_bits});
}
}
return collection_info;
}
mojom::HidCollectionInfoPtr HidCollection::ToMojo() const {
auto collection = mojom::HidCollectionInfo::New();
struct {
const std::unordered_map<uint8_t, HidReport>& in;
std::vector<mojom::HidReportDescriptionPtr>& out;
} report_lists[]{
{input_reports_, collection->input_reports},
{output_reports_, collection->output_reports},
{feature_reports_, collection->feature_reports},
};
collection->usage =
mojom::HidUsageAndPage::New(usage_.usage, usage_.usage_page);
collection->report_ids.insert(collection->report_ids.end(),
report_ids_.begin(), report_ids_.end());
collection->collection_type = collection_type_;
for (const auto& report_list : report_lists) {
for (const auto& report : report_list.in) {
auto report_description = mojom::HidReportDescription::New();
report_description->report_id = report.first;
for (const auto& item : report.second)
report_description->items.push_back(item->ToMojo());
report_list.out.push_back(std::move(report_description));
}
}
for (const auto& child : children_)
collection->children.push_back(child->ToMojo());
return collection;
}
} // namespace device
......@@ -40,14 +40,17 @@ class HidCollection {
uint32_t GetCollectionType() const { return collection_type_; }
// Returns true if there are one or more report IDs associated with this
// Return true if there are one or more report IDs associated with this
// collection.
bool HasReportId() const { return !report_ids_.empty(); }
// Returns information about the collection.
mojom::HidCollectionInfoPtr GetDetails(size_t* max_input_report_bits,
size_t* max_output_report_bits,
size_t* max_feature_report_bits);
// Compute the maximum size of any input, output, or feature report described
// by this collection.
void GetMaxReportSizes(size_t* max_input_report_bits,
size_t* max_output_report_bits,
size_t* max_feature_report_bits) const;
mojom::HidCollectionInfoPtr ToMojo() const;
const HidCollection* GetParent() const { return parent_; }
......
......@@ -46,7 +46,7 @@ class HidItemStateTable {
void Reset();
// Local items. See section 6.2.2.6 of the HID specifications.
// Local items. See section 6.2.2.8 of the HID specifications.
std::vector<uint32_t> usages;
uint32_t usage_minimum = 0;
uint32_t usage_maximum = 0;
......
......@@ -52,8 +52,8 @@ void HidReportDescriptor::GetDetails(
size_t input_bits;
size_t output_bits;
size_t feature_bits;
top_level_collections->push_back(
collection->GetDetails(&input_bits, &output_bits, &feature_bits));
collection->GetMaxReportSizes(&input_bits, &output_bits, &feature_bits);
top_level_collections->push_back(collection->ToMojo());
if (collection->HasReportId())
*has_report_id = true;
max_input_report_bits = std::max(max_input_report_bits, input_bits);
......
......@@ -93,29 +93,4 @@ uint32_t HidReportDescriptorItem::GetShortData() const {
return shortData_;
}
HidReportDescriptorItem::CollectionType
HidReportDescriptorItem::GetCollectionTypeFromValue(uint32_t value) {
switch (value) {
case 0x00:
return kCollectionTypePhysical;
case 0x01:
return kCollectionTypeApplication;
case 0x02:
return kCollectionTypeLogical;
case 0x03:
return kCollectionTypeReport;
case 0x04:
return kCollectionTypeNamedArray;
case 0x05:
return kCollectionTypeUsageSwitch;
case 0x06:
return kCollectionTypeUsageModifier;
default:
break;
}
if (0x80 < value && value < 0xFF)
return kCollectionTypeVendor;
return kCollectionTypeReserved;
}
} // namespace device
......@@ -122,21 +122,6 @@ class HidReportDescriptorItem {
static_assert(sizeof(ReportInfo) == sizeof(uint32_t),
"incorrect report info size");
// HID collection type.
// Can be retrieved from GetShortData()
// when item.tag() == HidReportDescriptorItem::kTagCollection
enum CollectionType {
kCollectionTypePhysical,
kCollectionTypeApplication,
kCollectionTypeLogical,
kCollectionTypeReport,
kCollectionTypeNamedArray,
kCollectionTypeUsageSwitch,
kCollectionTypeUsageModifier,
kCollectionTypeReserved,
kCollectionTypeVendor
};
private:
HidReportDescriptorItem(const uint8_t* bytes,
size_t size,
......@@ -175,8 +160,6 @@ class HidReportDescriptorItem {
// Size of this item in bytes, including the header.
size_t GetSize() const;
static CollectionType GetCollectionTypeFromValue(uint32_t value);
private:
size_t GetHeaderSize() const;
size_t payload_size() const { return payload_size_; }
......
......@@ -197,12 +197,10 @@ const HidReportDescriptorItem::Tag kOutput =
HidReportDescriptorItem::kTagOutput;
const HidReportDescriptorItem::Tag kFeature =
HidReportDescriptorItem::kTagFeature;
const HidReportDescriptorItem::CollectionType kCollectionTypeApplication =
HidReportDescriptorItem::kCollectionTypeApplication;
const HidReportDescriptorItem::CollectionType kCollectionTypeLogical =
HidReportDescriptorItem::kCollectionTypeLogical;
const HidReportDescriptorItem::CollectionType kCollectionTypePhysical =
kCollectionTypePhysical;
const uint32_t kCollectionTypeApplication =
mojom::kHIDCollectionTypeApplication;
const uint32_t kCollectionTypeLogical = mojom::kHIDCollectionTypeLogical;
const uint32_t kCollectionTypePhysical = mojom::kHIDCollectionTypePhysical;
} // namespace
......@@ -227,9 +225,7 @@ class HidReportDescriptorTest : public testing::Test {
}
// Create a new collection and append it to |expected_collections_|.
HidCollection* AddTopCollection(
uint32_t usage,
HidReportDescriptorItem::CollectionType collection_type) {
HidCollection* AddTopCollection(uint32_t usage, uint32_t collection_type) {
uint16_t usage_page = (usage >> kUsageIdSizeBits) & kUsageIdMask;
usage = usage & kUsageIdMask;
expected_collections_.push_back(std::make_unique<HidCollection>(
......@@ -238,10 +234,9 @@ class HidReportDescriptorTest : public testing::Test {
}
// Create a new collection as a child of |parent|.
HidCollection* AddChild(
HidCollection* parent,
uint32_t usage,
HidReportDescriptorItem::CollectionType collection_type) {
HidCollection* AddChild(HidCollection* parent,
uint32_t usage,
uint32_t collection_type) {
uint16_t usage_page = (usage >> kUsageIdSizeBits) & kUsageIdMask;
usage = usage & kUsageIdMask;
parent->AddChildForTesting(std::make_unique<HidCollection>(
......
......@@ -8,6 +8,16 @@
namespace device {
namespace {
mojom::HidUsageAndPagePtr ConvertUsageToMojo(uint32_t usage) {
uint16_t usage_id = usage & 0xffff;
uint16_t usage_page = (usage >> 16) & 0xffff;
return mojom::HidUsageAndPage::New(usage_id, usage_page);
}
} // namespace
HidReportItem::HidReportItem(HidReportDescriptorItem::Tag tag,
uint32_t short_data,
const HidItemStateTable& state)
......@@ -19,13 +29,7 @@ HidReportItem::HidReportItem(HidReportDescriptorItem::Tag tag,
global_(state.global_stack.empty()
? HidItemStateTable::HidGlobalItemState()
: state.global_stack.back()),
is_range_(state.local.usage_minimum != state.local.usage_maximum),
has_strings_(state.local.string_index ||
(state.local.string_minimum != state.local.string_maximum)),
has_designators_(
state.local.designator_index ||
(state.local.designator_minimum != state.local.designator_maximum)) {
global_.usage_page = mojom::kPageUndefined;
is_range_(state.local.usage_minimum != state.local.usage_maximum) {
if (state.local.string_index) {
local_.string_minimum = state.local.string_index;
local_.string_maximum = state.local.string_index;
......@@ -38,4 +42,42 @@ HidReportItem::HidReportItem(HidReportDescriptorItem::Tag tag,
HidReportItem::~HidReportItem() = default;
mojom::HidReportItemPtr HidReportItem::ToMojo() const {
auto report_item = mojom::HidReportItem::New();
report_item->is_range = is_range_;
// Data associated with the Main item.
report_item->is_constant = report_info_.data_or_constant;
report_item->is_variable = report_info_.array_or_variable;
report_item->is_relative = report_info_.absolute_or_relative;
report_item->wrap = report_info_.wrap;
report_item->is_non_linear = report_info_.linear;
report_item->no_preferred_state = report_info_.preferred;
report_item->has_null_position = report_info_.null;
report_item->is_volatile = report_info_.is_volatile;
report_item->is_buffered_bytes = report_info_.bit_field_or_buffer;
// Local items.
for (const auto& item : local_.usages)
report_item->usages.push_back(ConvertUsageToMojo(item));
report_item->usage_minimum = ConvertUsageToMojo(local_.usage_minimum);
report_item->usage_maximum = ConvertUsageToMojo(local_.usage_maximum);
report_item->designator_minimum = local_.designator_minimum;
report_item->designator_maximum = local_.designator_maximum;
report_item->string_minimum = local_.string_minimum;
report_item->string_maximum = local_.string_maximum;
// Global items.
report_item->logical_minimum = global_.logical_minimum;
report_item->logical_maximum = global_.logical_maximum;
report_item->physical_minimum = global_.physical_minimum;
report_item->physical_maximum = global_.physical_maximum;
report_item->unit_exponent = global_.unit_exponent;
report_item->unit = global_.unit;
report_item->report_size = global_.report_size;
report_item->report_count = global_.report_count;
return report_item;
}
} // namespace device
......@@ -13,6 +13,7 @@
#include "services/device/public/cpp/hid/hid_item_state_table.h"
#include "services/device/public/cpp/hid/hid_report_descriptor_item.h"
#include "services/device/public/mojom/hid.mojom.h"
namespace device {
......@@ -42,12 +43,6 @@ class HidReportItem {
// false if it defines a list of usages.
bool IsRange() const { return is_range_; }
// Returns true if the usage or usage range has one or more strings.
bool HasStrings() const { return has_strings_; }
// Returns true if the usage or usage range has one or more designators.
bool HasDesignators() const { return has_designators_; }
// Returns true if the report item is an absolute type, or false if it is a
// relative type.
bool IsAbsolute() const { return !report_info_.absolute_or_relative; }
......@@ -103,6 +98,8 @@ class HidReportItem {
int32_t GetPhysicalMinimum() const { return global_.physical_minimum; }
int32_t GetPhysicalMaximum() const { return global_.physical_maximum; }
mojom::HidReportItemPtr ToMojo() const;
private:
// The tag of the main item that generated this report item. Must be
// kItemInput, kItemOutput, or kItemFeature.
......@@ -122,12 +119,6 @@ class HidReportItem {
// If true, the usages for this item are defined by |local.usage_minimum| and
// |local.usage_maximum|. If false, the usages are defomed by |local.usages|.
bool is_range_;
// If true, one or more strings are associated with this item.
bool has_strings_;
// If true, one or more designators are associated with this item.
bool has_designators_;
};
} // namespace device
......
......@@ -42,10 +42,12 @@ const uint16 kPageMagneticStripeReader = 0x8E;
const uint16 kPageReservedPointOfSale = 0x8F;
const uint16 kPageCameraControl = 0x90;
const uint16 kPageArcade = 0x91;
const uint16 kPageFido = 0xF1D0;
const uint16 kPageVendor = 0xFF00;
const uint16 kPageMediaCenter = 0xFFBC;
// These usage enumerations are derived from the HID Usage Tables v1.11 spec.
// These usage enumerations are derived from the HID Usage Tables v1.12 spec.
// https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
const uint16 kGenericDesktopUndefined = 0x00;
const uint16 kGenericDesktopPointer = 0x01;
const uint16 kGenericDesktopMouse = 0x02;
......@@ -116,18 +118,137 @@ const uint16 kGenericDesktopSystemDisplayDual = 0xb4;
const uint16 kGenericDesktopSystemDisplayToggle = 0xb5;
const uint16 kGenericDesktopSystemDisplaySwap = 0xb6;
// These collection types are defined in section 6.2.2.6 of the Device Class
// Definition for HID.
// https://www.usb.org/sites/default/files/documents/hid1_11.pdf
const uint32 kHIDCollectionTypePhysical = 0x00;
const uint32 kHIDCollectionTypeApplication = 0x01;
const uint32 kHIDCollectionTypeLogical = 0x02;
const uint32 kHIDCollectionTypeReport = 0x03;
const uint32 kHIDCollectionTypeNamedArray = 0x04;
const uint32 kHIDCollectionTypeUsageSwitch = 0x05;
const uint32 kHIDCollectionTypeUsageModifier = 0x06;
const uint32 kHIDCollectionTypeVendorMin = 0x80;
const uint32 kHIDCollectionTypeVendorMax = 0xff;
struct HidUsageAndPage {
uint16 usage;
uint16 usage_page;
};
struct HidReportItem {
// True if the usages for this item are defined by |usage_minimum| and
// |usage_maximum|. False if the usages for this item are defined by |usages|.
bool is_range;
// Data associated with the Main item. See section 6.2.2.5 of the Device Class
// Definition for HID.
// https://www.usb.org/sites/default/files/documents/hid1_11.pdf
bool is_constant; // Constant (true) or Data (false).
bool is_variable; // Variable (true) or Array (false).
bool is_relative; // Relative (true) or Absolute (false).
bool wrap; // Wrap (true) or No Wrap (false).
bool is_non_linear; // Non Linear (true) or Linear (false).
bool no_preferred_state; // No Preferred (true) or Preferred State (false).
bool has_null_position; // Null state (true) or No Null position (false).
bool is_volatile; // Volatile (true) or Non Volatile (false).
bool is_buffered_bytes; // Buffered Bytes (true) or Bit Field (false).
// Local items. See section 6.2.2.8 of the Device Class Definition for HID.
// https://www.usb.org/sites/default/files/documents/hid1_11.pdf
// If |is_range| is false, usages for this item are listed in |usages| in the
// order they were encountered in the report descriptor.
array<HidUsageAndPage> usages;
// If |is_range| is true, usages for this item are assigned from a range of
// usages starting at |usage_minimum| and incrementing until |usage_maximum|.
// If this item is a Variable and |report_count| is larger than the number of
// usages in this range, all remaining fields are also assigned
// |usage_maximum|.
HidUsageAndPage usage_minimum;
HidUsageAndPage usage_maximum;
// If this item has one or more entries in the Physical descriptor table,
// |designator_minimum| and |designator_maximum| are set to the minimum and
// maximum indices of these entries. If the item has no designators, both are
// set to zero. A designator describes the body part intended to be used with
// a particular control.
uint32 designator_minimum;
uint32 designator_maximum;
// If this item has one or more entries in the String descriptor table,
// |string_minimum| and |string_maximum| are set to the minimum and maximum
// indices of these entries. If the item has no strings, both are set to zero.
// The String descriptor contains a list of text strings for the device.
uint32 string_minimum;
uint32 string_maximum;
// Global items. See section 6.2.2.7 of the Device Class Definition for HID.
// https://www.usb.org/sites/default/files/documents/hid1_11.pdf
// |logical_minimum| and |logical_maximum| define the extent of valid data
// values for the item in logical units. If |has_null_position| is true,
// values outside this range are interpreted as null input.
int32 logical_minimum;
int32 logical_maximum;
// |physical_minimum| and |physical_maximum| define the extent of valid data
// values after applying units to the logical extents.
int32 physical_minimum;
int32 physical_maximum;
// The value of the unit exponent in base 10. Values between 0x0 and 0x7
// represent positive exponents 0 to 7, values between 0x8 and 0xF represent
// nevative exponents -8 to -1. Bits [4:31] are reserved and should be set to
// zero.
uint32 unit_exponent;
// The units to apply to this item. The |unit| value is coded as seven 4-bit
// fields that define the unit system and the exponents on units of length,
// mass, time, temperature, current, and luminous intensity. Bits [28:31] are
// reserved and should be set to zero.
uint32 unit;
// A single report item may define multiple same-sized fields within a report.
// |report_size| and |report_count| define the size of one field (in bits) and
// the number of fields within the item. The total size of this item in bits
// is equal to the product of these values.
uint32 report_size;
uint32 report_count;
};
struct HidReportDescription {
// Report ID associated with this report, or zero if the device does not use
// report IDs.
uint8 report_id;
// The sequence of report items that describe this report.
array<HidReportItem> items;
};
struct HidCollectionInfo {
// Collection's usage ID.
HidUsageAndPage usage;
// HID report IDs which belong to this collection or to its
// embedded collections.
array<int32> report_ids;
// HID report IDs which belong to this collection or to its embedded
// collections, in the order they appear in the report descriptor.
array<uint8> report_ids;
// Collection type.
uint32 collection_type;
// Reports described in the report descriptor.
array<HidReportDescription> input_reports;
array<HidReportDescription> output_reports;
array<HidReportDescription> feature_reports;
// The children of this collection in the order they appear in the report
// descriptor. In child collections, the reports described in the
// |input_reports|, |output_reports|, and |feature_reports| members include
// only the subsequence of report items from the parent collection that appear
// within the child collection.
array<HidCollectionInfo> children;
};
struct HidDeviceInfo {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment