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