1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16#include "HidDefs.h" 17#include "HidParser.h" 18#include "HidLog.h" 19#include <iostream> 20#include <iomanip> 21 22namespace HidUtil { 23 24void HidParser::reset() { 25 mGlobalStack = HidGlobalStack(); 26 mLocal = HidLocal(); 27 mTree = std::make_shared<HidTreeNode>(); 28 mCurrent = mTree; 29} 30 31bool HidParser::parse(const std::vector<HidItem> &token) { 32 // Clean up internal states of the parser for a new stream of descriptor token 33 reset(); 34 35 bool ret = true; 36 using namespace HidDef::TagType; 37 38 for (auto &i : token) { 39 switch (i.type) { 40 case MAIN: 41 ret = processMainTag(i); 42 break; 43 case GLOBAL: 44 ret = mGlobalStack.append(i); 45 break; 46 case LOCAL: 47 ret = mLocal.append(i); 48 break; 49 default: 50 LOG_E << "HidParser found illegal HidItem: " << i << LOG_ENDL; 51 ret = false; 52 } 53 54 // in case a parse failure, quit prematurely 55 if (!ret) { 56 break; 57 } 58 } 59 return ret; 60} 61 62bool HidParser::processMainTag(const HidItem &i) { 63 using namespace HidDef::MainTag; 64 using namespace HidDef::ReportFlag; 65 66 bool ret = true; 67 switch (i.tag) { 68 case COLLECTION: { 69 unsigned int collectionType; 70 if (!i.dataAsUnsigned(&collectionType)) { 71 LOG_E << "Cannot get collection type at offset " << i.offset << LOG_ENDL; 72 ret = false; 73 break; 74 } 75 unsigned int fullUsage = 76 mGlobalStack.top().usagePage.get(0) << 16 | mLocal.getUsage(0); 77 mCurrent = mCurrent->addChild( 78 std::make_shared<HidTreeNode>(mCurrent, collectionType, fullUsage)); 79 break; 80 } 81 case END_COLLECTION: 82 mCurrent = mCurrent->getParent(); 83 if (!mCurrent) { 84 // trigger parse failure so that mCurrent will not be accessed 85 LOG_E << "unmatched END_COLLECTION at " << i.offset << LOG_ENDL; 86 ret = false; 87 } 88 break; 89 case INPUT: 90 case OUTPUT: 91 case FEATURE: { 92 unsigned int reportType = i.tag; 93 unsigned int flag; 94 if (!i.dataAsUnsigned(&flag)) { 95 LOG_E << "Cannot get report flag at offset " << i.offset << LOG_ENDL; 96 ret = false; 97 break; 98 } 99 const HidGlobal &top = mGlobalStack.top(); 100 101 // usage page, local min/max, report size and count have to be defined at report 102 // definition. 103 if (!(top.usagePage.isSet() && top.logicalMin.isSet() && top.logicalMax.isSet() 104 && top.reportSize.isSet() && top.reportCount.isSet())) { 105 LOG_E << "Report defined at " << i.offset 106 << " does not have all mandatory fields set" << LOG_ENDL; 107 ret = false; 108 break; 109 } 110 if (top.reportSize.get(0) > 32) { 111 LOG_E << "Report defined at " << i.offset 112 << " has unsupported report size(> 32 bit)" << LOG_ENDL; 113 ret = false; 114 break; 115 } 116 117 HidReport report(reportType, flag, top, mLocal); 118 mReport.push_back(report); 119 std::shared_ptr<HidTreeNode> node(new HidReportNode(mCurrent, report)); 120 mCurrent->addChild(node); 121 break; 122 } 123 default: 124 LOG_E << "unknown main tag, " << i << LOG_ENDL; 125 ret = false; 126 } 127 // locals is cleared after any main tag according to HID spec 128 mLocal.clear(); 129 return ret; 130} 131 132bool HidParser::parse(const unsigned char *begin, size_t size) { 133 std::vector<HidItem> hidItemVector = HidItem::tokenize(begin, size); 134 return parse(hidItemVector); 135} 136 137void HidParser::filterTree() { 138 if (mTree != nullptr) { 139 filterTree(mTree); 140 } 141} 142 143void HidParser::filterTree(std::shared_ptr<HidTreeNode> &node) { 144 if (node->isReportCollection()) { 145 std::shared_ptr<HidReportNode> reportNode = 146 std::static_pointer_cast<HidReportNode>(node->getChildren().front()); 147 if (reportNode != nullptr) { 148 reportNode->collapse(node->getFullUsage()); 149 node = reportNode; 150 } 151 } else { 152 for (auto &i : node->getChildren()) { 153 filterTree(i); 154 } 155 } 156} 157 158HidParser::DigestVector HidParser::generateDigest( 159 const std::unordered_set<unsigned int> &interestedUsage) { 160 DigestVector digestVector; 161 digest(&digestVector, mTree, interestedUsage); 162 return digestVector; 163} 164 165void HidParser::digest(HidParser::DigestVector *digestVector, 166 const std::shared_ptr<HidTreeNode> &node, 167 const std::unordered_set<unsigned int> &interestedUsage) { 168 if (digestVector == nullptr) { 169 return; 170 } 171 172 if (node->isUsageCollection() 173 && interestedUsage.find(node->getFullUsage()) != interestedUsage.end()) { 174 // this collection contains the usage interested 175 ReportSetGroup reportSetGroup; 176 177 // one layer deep search 178 for (auto &i : node->getChildren()) { 179 // skip all nodes that is not a report node 180 if (i->getNodeType() != HidTreeNode::TYPE_REPORT) { 181 continue; 182 } 183 const HidReport &report = 184 std::static_pointer_cast<HidReportNode>(i)->getReport(); 185 186 unsigned int id = report.getReportId();; 187 if (reportSetGroup.find(id) == reportSetGroup.end()) { 188 // create an id group if it is not created 189 reportSetGroup.emplace(id, ReportSet()); 190 } 191 192 ReportSet &reportGroup = reportSetGroup[id]; 193 switch(report.getType()) { 194 using namespace HidDef::MainTag; 195 case FEATURE: 196 reportGroup[REPORT_TYPE_FEATURE].push_back(report); 197 break; 198 case INPUT: 199 reportGroup[REPORT_TYPE_INPUT].push_back(report); 200 break; 201 case OUTPUT: 202 reportGroup[REPORT_TYPE_OUTPUT].push_back(report); 203 break; 204 } 205 } 206 ReportDigest digest = { 207 .fullUsage = node->getFullUsage(), 208 .packets = convertGroupToPacket(reportSetGroup) 209 }; 210 digestVector->emplace_back(digest); 211 } else { 212 for (const auto &child : node->getChildren()) { 213 if (child->getNodeType() == HidTreeNode::TYPE_NORMAL) { 214 // only follow into collection nodes 215 digest(digestVector, child, interestedUsage); 216 } 217 } 218 } 219} 220 221std::vector<HidParser::ReportPacket> HidParser::convertGroupToPacket( 222 const HidParser::ReportSetGroup &group) { 223 std::vector<ReportPacket> packets; 224 225 const std::vector<int> types = {REPORT_TYPE_FEATURE, REPORT_TYPE_INPUT, REPORT_TYPE_OUTPUT}; 226 227 for (const auto &setPair : group) { 228 unsigned int id = setPair.first; 229 for (auto type : types) { 230 const auto &reports = setPair.second[type]; // feature 231 232 // template 233 ReportPacket packet = { 234 .type = type, 235 .id = id, 236 .bitSize = 0 237 }; 238 239 for (const auto &r : reports) { 240 auto logical = r.getLogicalRange(); 241 auto physical = r.getPhysicalRange(); 242 243 int64_t offset = physical.first - logical.first; 244 double scale = static_cast<double>((physical.second - physical.first)) 245 / (logical.second - logical.first); 246 scale *= r.getExponentValue(); 247 248 ReportItem digest = { 249 .usage = r.getFullUsage(), 250 .id = id, 251 .minRaw = logical.first, 252 .maxRaw = logical.second, 253 .a = scale, 254 .b = offset, 255 .bitOffset = packet.bitSize, 256 .bitSize = r.getSize(), 257 .count = r.getCount(), 258 .unit = r.getUnit(), 259 }; 260 packet.reports.push_back(digest); 261 packet.bitSize += digest.bitSize * digest.count; 262 } 263 if (!packet.reports.empty()) { 264 packets.push_back(std::move(packet)); 265 } 266 } 267 } 268 return packets; 269} 270 271static std::string reportTypeToString(int reportType) { 272 switch (reportType) { 273 case HidParser::REPORT_TYPE_INPUT: 274 return "INPUT"; 275 case HidParser::REPORT_TYPE_OUTPUT: 276 return "OUTPUT"; 277 case HidParser::REPORT_TYPE_FEATURE: 278 return "FEATURE"; 279 default: 280 return "INVALID REPORT"; 281 } 282} 283 284std::ostream& operator<<(std::ostream &os, const HidParser::DigestVector &digests) { 285 for (const auto &i : digests) { 286 os << "Usage: 0x" << std::hex << i.fullUsage << std::dec 287 << ", " << i.packets.size() << " report packet:" << LOG_ENDL; 288 for (const auto &packet : i.packets) { 289 os << reportTypeToString(packet.type) << " id: " << packet.id 290 << " size: " << packet.bitSize 291 << "b(" << packet.getByteSize() << "B), " 292 << packet.reports.size() << " entries" << LOG_ENDL; 293 294 for (const auto &report : packet.reports) { 295 double min, max; 296 report.decode(report.mask(report.minRaw), &min); 297 report.decode(report.mask(report.maxRaw), &max); 298 299 os << " " << report.bitOffset << " size: " << report.bitSize 300 << ", count: " << report.count 301 << ", usage: " << std::hex << std::setfill('0') << std::setw(8) 302 << report.usage << std::dec 303 << ", min: " << report.minRaw << ", max: " << report.maxRaw 304 << ", minDecoded: " << min 305 << ", maxDecoded: " << max 306 << ", a: " << report.a << ", b: " << report.b 307 << std::hex 308 << ", minRawHex: 0x" << report.mask(report.minRaw) 309 << ", maxRawHex: 0x" << report.mask(report.maxRaw) 310 << ", rawMasked: 0x" << report.rawMask() 311 << std::dec << LOG_ENDL; 312 } 313 } 314 os << LOG_ENDL; 315 } 316 os << LOG_ENDL; 317 return os; 318} 319} // namespace HidUtil 320