15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved.
25c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Use of this source code is governed by a BSD-style license that can be
35c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// found in the LICENSE file.
45c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
55c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "device/hid/hid_report_descriptor_item.h"
65c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include <stdlib.h>
85c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/logging.h"
105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "device/hid/hid_usage_and_page.h"
115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace device {
135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace {
155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liustruct Header {
175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  uint8_t size : 2;
185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  uint8_t type : 2;
195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  uint8_t tag : 4;
205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}  // namespace
235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuHidReportDescriptorItem::HidReportDescriptorItem(
255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const uint8_t* bytes,
265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    HidReportDescriptorItem* previous)
275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    : previous_(previous), next_(NULL), parent_(NULL), shortData_(0) {
285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  Header* header = (Header*)&bytes[0];
295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  tag_ = (Tag)(header->tag << 2 | header->type);
305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (IsLong()) {
325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // In a long item, payload size is the second byte.
335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    payload_size_ = bytes[1];
345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  } else {
355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    payload_size_ = header->size;
365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DCHECK(payload_size_ <= sizeof(shortData_));
375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    memcpy(&shortData_, &bytes[GetHeaderSize()], payload_size());
385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (previous) {
415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DCHECK(!previous->next_);
425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    previous->next_ = this;
435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    switch (previous->tag()) {
445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      case kTagCollection:
455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        parent_ = previous;
465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        break;
475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      default:
485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        break;
495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (!parent_) {
515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      switch (tag()) {
525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        case kTagEndCollection:
535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          if (previous->parent()) {
545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu            parent_ = previous->parent()->parent();
555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          }
565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          break;
575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        default:
585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          parent_ = previous->parent();
595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          break;
605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      }
615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liusize_t HidReportDescriptorItem::GetDepth() const {
665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  HidReportDescriptorItem* parent_item = parent();
675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (parent_item)
685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return parent_item->GetDepth() + 1;
695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return 0;
705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool HidReportDescriptorItem::IsLong() const { return tag() == kTagLong; }
735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liusize_t HidReportDescriptorItem::GetHeaderSize() const {
755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return IsLong() ? 3 : 1;
765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liusize_t HidReportDescriptorItem::GetSize() const {
795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return GetHeaderSize() + payload_size();
805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuuint32_t HidReportDescriptorItem::GetShortData() const {
835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(!IsLong());
845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return shortData_;
855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuHidReportDescriptorItem::CollectionType
885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuHidReportDescriptorItem::GetCollectionTypeFromValue(uint32_t value) {
895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  switch (value) {
905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case 0x00:
915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return kCollectionTypePhysical;
925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case 0x01:
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return kCollectionTypeApplication;
945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case 0x02:
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return kCollectionTypeLogical;
965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case 0x03:
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return kCollectionTypeReport;
985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case 0x04:
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return kCollectionTypeNamedArray;
1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case 0x05:
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return kCollectionTypeUsageSwitch;
1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case 0x06:
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return kCollectionTypeUsageModifier;
1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    default:
1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      break;
1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (0x80 < value && value < 0xFF)
1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return kCollectionTypeVendor;
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return kCollectionTypeReserved;
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}  // namespace device
113