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
22 namespace HidUtil {
23
reset()24 void HidParser::reset() {
25 mGlobalStack = HidGlobalStack();
26 mLocal = HidLocal();
27 mTree = std::make_shared<HidTreeNode>();
28 mCurrent = mTree;
29 }
30
parse(const std::vector<HidItem> & token)31 bool 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
processMainTag(const HidItem & i)62 bool 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
parse(const unsigned char * begin,size_t size)132 bool HidParser::parse(const unsigned char *begin, size_t size) {
133 std::vector<HidItem> hidItemVector = HidItem::tokenize(begin, size);
134 return parse(hidItemVector);
135 }
136
filterTree()137 void HidParser::filterTree() {
138 if (mTree != nullptr) {
139 filterTree(mTree);
140 }
141 }
142
filterTree(std::shared_ptr<HidTreeNode> & node)143 void 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
generateDigest(const std::unordered_set<unsigned int> & interestedUsage)158 HidParser::DigestVector HidParser::generateDigest(
159 const std::unordered_set<unsigned int> &interestedUsage) {
160 DigestVector digestVector;
161 digest(&digestVector, mTree, interestedUsage);
162 return digestVector;
163 }
164
digest(HidParser::DigestVector * digestVector,const std::shared_ptr<HidTreeNode> & node,const std::unordered_set<unsigned int> & interestedUsage)165 void 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
convertGroupToPacket(const HidParser::ReportSetGroup & group)221 std::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 .bitSize = 0,
235 .type = type,
236 .id = id,
237 };
238
239 for (const auto &r : reports) {
240 auto logical = r.getLogicalRange();
241 auto physical = r.getPhysicalRange();
242
243 double scale;
244 if ((physical.first != physical.second) &&
245 (logical.first != logical.second)) {
246 scale = static_cast<double>(physical.second - physical.first)
247 / (logical.second - logical.first);
248 } else {
249 scale = (physical.first != 0) ? physical.first : 1.0;
250 }
251 scale *= r.getExponentValue();
252 int64_t offset =
253 (physical.first * r.getExponentValue() / scale) -
254 logical.first;
255
256 ReportItem digest = {
257 .usage = r.getFullUsage(),
258 .id = id,
259 .usageVector = r.getUsageVector(),
260 .minRaw = logical.first,
261 .maxRaw = logical.second,
262 .a = scale,
263 .b = offset,
264 .unit = r.getUnit(),
265 .bitOffset = packet.bitSize,
266 .bitSize = r.getSize(),
267 .count = r.getCount(),
268 };
269 packet.reports.push_back(digest);
270 packet.bitSize += digest.bitSize * digest.count;
271 }
272 if (!packet.reports.empty()) {
273 packets.push_back(std::move(packet));
274 }
275 }
276 }
277 return packets;
278 }
279
reportTypeToString(int reportType)280 static std::string reportTypeToString(int reportType) {
281 switch (reportType) {
282 case HidParser::REPORT_TYPE_INPUT:
283 return "INPUT";
284 case HidParser::REPORT_TYPE_OUTPUT:
285 return "OUTPUT";
286 case HidParser::REPORT_TYPE_FEATURE:
287 return "FEATURE";
288 default:
289 return "INVALID REPORT";
290 }
291 }
292
operator <<(std::ostream & os,const HidParser::DigestVector & digests)293 std::ostream& operator<<(std::ostream &os, const HidParser::DigestVector &digests) {
294 for (const auto &i : digests) {
295 os << "Usage: 0x" << std::hex << i.fullUsage << std::dec
296 << ", " << i.packets.size() << " report packet:" << LOG_ENDL;
297 for (const auto &packet : i.packets) {
298 os << reportTypeToString(packet.type) << " id: " << packet.id
299 << " size: " << packet.bitSize
300 << "b(" << packet.getByteSize() << "B), "
301 << packet.reports.size() << " entries" << LOG_ENDL;
302
303 for (const auto &report : packet.reports) {
304 double min, max;
305 report.decode(report.mask(report.minRaw), &min);
306 report.decode(report.mask(report.maxRaw), &max);
307
308 os << " " << report.bitOffset << " size: " << report.bitSize
309 << ", count: " << report.count
310 << ", usage: " << std::hex << std::setfill('0') << std::setw(8)
311 << report.usage << std::dec
312 << ", min: " << report.minRaw << ", max: " << report.maxRaw
313 << ", minDecoded: " << min
314 << ", maxDecoded: " << max
315 << ", a: " << report.a << ", b: " << report.b
316 << std::hex
317 << ", minRawHex: 0x" << report.mask(report.minRaw)
318 << ", maxRawHex: 0x" << report.mask(report.maxRaw)
319 << ", rawMasked: 0x" << report.rawMask()
320 << std::dec << LOG_ENDL;
321 }
322 }
323 os << LOG_ENDL;
324 }
325 os << LOG_ENDL;
326 return os;
327 }
328
329 } // namespace HidUtil
330