blob: ce55d3f19901d233d2ed7a151890de548365c2df [file] [log] [blame]
// Copyright 2017 The Fuchsia 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 "hid-parser/item.h"
#include <zircon/assert.h>
namespace hid {
namespace impl {
Item::Tag get_main_tag(uint8_t b_tag) {
switch (b_tag) {
case 8: return Item::Tag::kInput;
case 9: return Item::Tag::kOutput;
case 10: return Item::Tag::kCollection;
case 11: return Item::Tag::kFeature;
case 12: return Item::Tag::kEndCollection;
default: return Item::Tag::kReserved;
}
}
Item::Tag get_global_tag(uint8_t b_tag) {
switch (b_tag) {
case 0: return Item::Tag::kUsagePage;
case 1: return Item::Tag::kLogicalMinimum;
case 2: return Item::Tag::kLogicalMaximum;
case 3: return Item::Tag::kPhysicalMinimum;
case 4: return Item::Tag::kPhysicalMaximum;
case 5: return Item::Tag::kUnitExponent;
case 6: return Item::Tag::kUnit;
case 7: return Item::Tag::kReportSize;
case 8: return Item::Tag::kReportId;
case 9: return Item::Tag::kReportCount;
case 10: return Item::Tag::kPush;
case 11: return Item::Tag::kPop;
default: return Item::Tag::kReserved;
}
}
Item::Tag get_local_tag(uint8_t b_tag) {
switch (b_tag) {
case 0: return Item::Tag::kUsage;
case 1: return Item::Tag::kUsageMinimum;
case 2: return Item::Tag::kUsageMaximum;
case 3: return Item::Tag::kDesignatorIndex;
case 4: return Item::Tag::kDesignatorMinimum;
case 5: return Item::Tag::kDesignatorMaximum;
// No tag for 6.
case 7: return Item::Tag::kStringIndex;
case 8: return Item::Tag::kStringMinimum;
case 9: return Item::Tag::kStringMaximum;
case 10: return Item::Tag::kDelimiter;
default: return Item::Tag::kReserved;
}
}
// This is the bit pattern for long items which this
// library does not support.
constexpr uint8_t kLongItemMarker = 0xfe;
Item::Type get_type_and_size(uint8_t data, size_t* size) {
if (data == kLongItemMarker)
return Item::Type::kLongItem;
// Short item.
// Payload size is 0,1,2,4 bytes.
auto b_size = (data & 0x03);
*size = ( b_size != 3) ? b_size : 4;
switch ((data >> 2) & 0x03) {
case 0: return Item::Type::kMain;
case 1: return Item::Type::kGlobal;
case 2: return Item::Type::kLocal;
default: return Item::Type::kReserved;
}
}
Item::Tag get_tag(Item::Type type, uint8_t data) {
uint8_t b_tag = (data >> 4) & 0x0f;
switch (type) {
case Item::Type::kMain: return get_main_tag(b_tag);
case Item::Type::kGlobal: return get_global_tag(b_tag);
case Item::Type::kLocal: return get_local_tag(b_tag);
default: return Item::Tag::kReserved;
}
}
} // namespace impl.
Item Item::ReadNext(const uint8_t* data, size_t len, size_t* actual) {
ZX_DEBUG_ASSERT(len != 0);
size_t size = 0;
auto type = impl::get_type_and_size(data[0], &size);
auto tag = impl::get_tag(type, data[0]);
// Amount to parse is 1-byte for the header and |size| for the payload
// for short items. Long items are not supported.
*actual = (type != Item::Type::kLongItem) ? 1 + size : 0;
uint32_t item_data = 0;
if (*actual <= len) {
for (size_t ix = 0; ix < size; ++ix) {
item_data |= data[1 + ix] << (8 * ix);
}
}
return Item(type, tag, item_data);
}
} // namespace hid