1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <stdint.h>
8 #include <stdlib.h>
9 
10 namespace hid {
11 
12 // The hid report descriptor parser consists of a single function
13 // ParseReportDescriptor() that takes as input a USB report descriptor
14 // byte stream and on success returns a heap-allocated DeviceDescriptor
15 // structure. When not needed it can be freed via FreeDeviceDescriptor().
16 //
17 // The DeviceDescriptor data is organized at the first level by the
18 // array |report[rep_count]| in which each entry points to the first
19 // field of each report and how many fields are expected on each report.
20 //
21 // report[0].first_field --->  ReportField
22 //                              +report_id
23 //                              +field_type
24 //                              +col -------> Collection
25 //                                            +type
26 //                                            +parent ---> Collection
27 //                             1
28 // The structure describes all the information returned by the device;
29 // no information present in the original stream is lost.
30 //
31 // When using it to parse reports sent by the device, two scenarios
32 // are important:
33 //   1 -  |rep_count| is 1 and report[0]->report_id is 0:
34 //      in this case the reports don't have a report id tag and the
35 //      first byte in the stream contains the first field.
36 //   2 - report[0]->report_id is not 0:
37 //      in this case each report first byte is the report_id tag
38 //      and must be matched to properly decode the report.
39 //
40 // Once the right starting ReportField has been matched then extracting
41 // each field is done by inspecting bit_sz and flags and using |next|
42 // to move to the following field. Reaching |next| == null means the
43 // end of the report.
44 //
45 // An example will enlighten. Assume |report| array as follows,
46 // with most fields omitted for brevity:
47 //
48 //    report[0]
49 //    .first_field--> [0] report_id:      1
50 //                        usage           button,1
51 //                        flags           data,var
52 //                        bit_sz          1
53 //
54 //                    [1] report_id:      1
55 //                        usage           button,2
56 //                        flags           data,var
57 //                        bit_sz          1
58 //
59 //                    [2] report_id:      1
60 //                        usage           button,none
61 //                        flags           const
62 //                        bit_sz          6
63 //    report[1]
64 //    .first_field--> [3] report_id:      3
65 //                        usage           desktop,X
66 //                        flags           data,var
67 //                        bit_sz          8
68 //
69 //                    [4] report_id:      3
70 //                        usage           desktop,Y
71 //                        flags           data,var
72 //                        bit_sz          8
73 //    report[2]
74 //    .first_field--> [5] report_id:      4
75 //                        usage           desktop,wheel
76 //                        flags           data,var
77 //                        bit_sz          5
78 //
79 //                    [6] report_id:      4
80 //                        usage           desktop,none
81 //                        flags           const
82 //                        bit_sz          3
83 //
84 // Now given the following report stream, with byte-order
85 // left to right:
86 //
87 //   03 b4 67 01 02 04 13 03 b5 6a
88 //   ------>--------->----------->
89 //
90 //  Can be parsed as the following 4 reports:
91 //
92 //  - 03 is report id, so Node [3] and Node [4] are in play
93 //       b4 is X-coord/desktop  (8-bits)
94 //       67 is Y-coord/desktop  (8-bits)
95 //
96 //  - 01 is report id, so Node [0], Node [1] and Node [3] are in play
97 //       02 is split into bits
98 //          0 is 1/button (1-bit)
99 //          1 is 2/button (1-bit)
100 //          0 is none/button (7-bit)       padding
101 //
102 //  - 04 is report id, so Node [5] and Node [6] are in play
103 //       13 is split into bits
104 //          13 is desktop/wheel (5-bit)
105 //           0 is desktop/none  (3-bit)    padding
106 //
107 //  - 03 is report id, so Node [3] and Node [4] are in play
108 //       b5 is X-coord/desktop  (8-bits)
109 //       6a is Y-coord/desktop  (8-bits)
110 //
111 //
112 
113 // Logical minimum and maximum per hid spec.
114 struct MinMax {
115     int32_t min;
116     int32_t max;
117 };
118 
119 // Physical units descriptor.
120 struct Unit {
121     uint32_t type;
122     int32_t exp;
123 };
124 
125 // Describes the semantic meaning of fields. See the "HID Usage tables"
126 // document from usb.org.
127 struct Usage {
128     uint16_t page;
129     uint32_t usage;
130 };
131 
132 enum class CollectionType : uint32_t {
133     kPhysical,
134     kApplication,
135     kLogical,
136     kReport,
137     kNamedArray,
138     kUsageSwitch,
139     kUsageModifier,
140     kReserved,
141     kVendor
142 };
143 
144 enum NodeType : uint32_t {
145     kInput,
146     kOutput,
147     kFeature
148 };
149 
150 enum FieldTypeFlags : uint32_t {
151     // Indicates if field can be modfied. Constant often means is padding.
152     kData               = 1 << 0,
153     kConstant           = 1 << 1,
154     // The field is either an array or scalar. If it is an array only
155     // the kData|kConstant and kAbsolute|kRelative flags are valid.
156     kArray              = 1 << 2,
157     kScalar             = 1 << 3,
158     // Value is absolute wrt to a fixed origin or not.
159     kAbsolute           = 1 << 4,
160     kRelative           = 1 << 5,
161     // Whether the data rolls over wrt to the logical min/max.
162     kNoWrap             = 1 << 6,
163     kWrap               = 1 << 7,
164     // Data has been pre-processed, for example dead-zone.
165     kLinear             = 1 << 8,
166     kNonLinear          = 1 << 9,
167     // Value returns to a preset value when the user is not interacting with control.
168     kPreferredState     = 1 << 10,
169     kNoPreferred        = 1 << 11,
170     // If the control can enter a state when it does not report data.
171     kNoNullPosition     = 1 << 12,
172     kNullState          = 1 << 13,
173     // Output-only: can the value be modified without host interaction.
174     kNonVolatile        = 1 << 14,
175     kVolatile           = 1 << 15,
176     // Data is a fixed size stream.
177     kBitField           = 1 << 16,
178     kBufferedBytes      = 1 << 17,
179 };
180 
181 // TODO(cpu): consider repurposing the kData| kArray | kNonLinear to indicate
182 // an array field which requires a lookup table. See adafruit trinket report id 4
183 // for an example of this case.
184 
185 struct Collection {
186     CollectionType type;
187     Usage usage;
188     Collection* parent;            // Enclosing collection or null.
189 };
190 
191 struct Attributes {
192     Usage usage;
193     Unit unit;
194     MinMax logc_mm;
195     MinMax phys_mm;
196     uint8_t bit_sz;
197 };
198 
199 struct ReportField {
200     uint8_t report_id;
201     Attributes attr;
202     NodeType type;
203     uint32_t flags;
204     Collection* col;
205 };
206 
207 struct ReportDescriptor {
208     uint8_t report_id;
209     size_t count;
210     ReportField* first_field;
211 };
212 
213 struct DeviceDescriptor {
214     size_t rep_count;
215     ReportDescriptor report[];
216 };
217 
218 enum ParseResult : uint32_t {
219     kParseOk                 = 0,
220     kParseNoMemory           = 1,
221     kParseMoreNeeded         = 2,
222     kParseUnsuported         = 3,
223     kParseInvalidTag         = 4,
224     kParseInvalidItemType    = 5,
225     kParseInvalidItemValue   = 6,
226     kParseUsageLimit         = 7,
227     kParseInvalidRange       = 8,
228     kParseOverflow           = 9,
229     kParseLeftovers          = 10,
230     kParseUnexpectedCol      = 11,
231     kParseUnexectedItem      = 12,
232     kParseInvalidUsage       = 13,
233     kParseMissingUsage       = 14,
234     kParserMissingPage       = 15,
235     kParserUnexpectedPop     = 16,
236     kParserInvalidID         = 17
237 };
238 
239 ParseResult ParseReportDescriptor(
240     const uint8_t* rpt_desc, size_t desc_len,
241     DeviceDescriptor** dev_desc);
242 
243 void FreeDeviceDescriptor(DeviceDescriptor* dev_desc);
244 
245 ReportField* GetFirstInputField(const DeviceDescriptor* dev_desc,
246                                 size_t* count);
247 
248 Collection* GetAppCollection(const ReportField* field);
249 
250 
251 }  // namespace hid
252