1 /* 2 * Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #ifndef USERLAND_HID 7 #include "Driver.h" 8 #else 9 #include "UserlandHID.h" 10 #endif 11 12 #include "HIDCollection.h" 13 #include "HIDReport.h" 14 #include "HIDReportItem.h" 15 16 #include <new> 17 #include <stdlib.h> 18 #include <string.h> 19 20 21 HIDCollection::HIDCollection(HIDCollection *parent, uint8 type, 22 local_item_state &localState) 23 : fParent(parent), 24 fType(type), 25 fStringID(localState.string_index), 26 fPhysicalID(localState.designator_index), 27 fChildCount(0), 28 fChildren(NULL), 29 fItemCount(0), 30 fItemsAllocated(0), 31 fItems(NULL) 32 { 33 usage_value usageValue; 34 if (localState.usage_stack != NULL && localState.usage_stack_used > 0) 35 usageValue.u.extended = localState.usage_stack[0].u.extended; 36 else if (localState.usage_minimum_set) 37 usageValue.u.extended = localState.usage_minimum.u.extended; 38 else if (localState.usage_maximum_set) 39 usageValue.u.extended = localState.usage_maximum.u.extended; 40 else if (type == COLLECTION_LOGICAL) { 41 // this is just a logical grouping collection 42 usageValue.u.extended = 0; 43 } else { 44 TRACE_ALWAYS("none of the possible usages for the collection are " 45 "set\n"); 46 } 47 48 fUsage = usageValue.u.extended; 49 } 50 51 52 HIDCollection::~HIDCollection() 53 { 54 for (uint32 i = 0; i < fChildCount; i++) 55 delete fChildren[i]; 56 free(fChildren); 57 free(fItems); 58 } 59 60 61 uint16 62 HIDCollection::UsagePage() 63 { 64 usage_value value; 65 value.u.extended = fUsage; 66 return value.u.s.usage_page; 67 } 68 69 70 uint16 71 HIDCollection::UsageID() 72 { 73 usage_value value; 74 value.u.extended = fUsage; 75 return value.u.s.usage_id; 76 } 77 78 79 status_t 80 HIDCollection::AddChild(HIDCollection *child) 81 { 82 HIDCollection **newChildren = (HIDCollection **)realloc(fChildren, 83 (fChildCount + 1) * sizeof(HIDCollection *)); 84 if (newChildren == NULL) { 85 TRACE_ALWAYS("no memory when trying to resize collection child list\n"); 86 return B_NO_MEMORY; 87 } 88 89 fChildren = newChildren; 90 fChildren[fChildCount++] = child; 91 return B_OK; 92 } 93 94 95 HIDCollection * 96 HIDCollection::ChildAt(uint32 index) 97 { 98 if (index >= fChildCount) 99 return NULL; 100 101 return fChildren[index]; 102 } 103 104 105 uint32 106 HIDCollection::CountChildrenFlat(uint8 type) 107 { 108 uint32 count = 0; 109 if (type == COLLECTION_ALL || fType == type) 110 count++; 111 112 for (uint32 i = 0; i < fChildCount; i++) { 113 HIDCollection *child = fChildren[i]; 114 if (child == NULL) 115 continue; 116 117 count += child->CountChildrenFlat(type); 118 } 119 120 return count; 121 } 122 123 124 HIDCollection * 125 HIDCollection::ChildAtFlat(uint8 type, uint32 index) 126 { 127 return _ChildAtFlat(type, index); 128 } 129 130 131 void 132 HIDCollection::AddItem(HIDReportItem *item) 133 { 134 if (fItemCount >= fItemsAllocated) { 135 fItemsAllocated += 10; 136 HIDReportItem **newItems = (HIDReportItem **)realloc(fItems, 137 fItemsAllocated * sizeof(HIDReportItem *)); 138 if (newItems == NULL) { 139 TRACE_ALWAYS("no memory when trying to resize collection items\n"); 140 fItemsAllocated -= 10; 141 return; 142 } 143 144 fItems = newItems; 145 } 146 147 fItems[fItemCount++] = item; 148 } 149 150 151 HIDReportItem * 152 HIDCollection::ItemAt(uint32 index) 153 { 154 if (index >= fItemCount) 155 return NULL; 156 157 return fItems[index]; 158 } 159 160 161 uint32 162 HIDCollection::CountItemsFlat() 163 { 164 uint32 count = fItemCount; 165 166 for (uint32 i = 0; i < fChildCount; i++) { 167 HIDCollection *child = fChildren[i]; 168 if (child != NULL) 169 count += child->CountItemsFlat(); 170 } 171 172 return count; 173 } 174 175 176 HIDReportItem * 177 HIDCollection::ItemAtFlat(uint32 index) 178 { 179 return _ItemAtFlat(index); 180 } 181 182 183 void 184 HIDCollection::PrintToStream(uint32 indentLevel) 185 { 186 char indent[indentLevel + 1]; 187 memset(indent, '\t', indentLevel); 188 indent[indentLevel] = 0; 189 190 const char *typeName = "unknown"; 191 switch (fType) { 192 case COLLECTION_PHYSICAL: 193 typeName = "physical"; 194 break; 195 case COLLECTION_APPLICATION: 196 typeName = "application"; 197 break; 198 case COLLECTION_LOGICAL: 199 typeName = "logical"; 200 break; 201 case COLLECTION_REPORT: 202 typeName = "report"; 203 break; 204 case COLLECTION_NAMED_ARRAY: 205 typeName = "named array"; 206 break; 207 case COLLECTION_USAGE_SWITCH: 208 typeName = "usage switch"; 209 break; 210 case COLLECTION_USAGE_MODIFIER: 211 typeName = "usage modifier"; 212 break; 213 } 214 215 TRACE_ALWAYS("%sHIDCollection %p\n", indent, this); 216 TRACE_ALWAYS("%s\ttype: %u %s\n", indent, fType, typeName); 217 TRACE_ALWAYS("%s\tusage: 0x%08" B_PRIx32 "\n", indent, fUsage); 218 TRACE_ALWAYS("%s\tstring id: %u\n", indent, fStringID); 219 TRACE_ALWAYS("%s\tphysical id: %u\n", indent, fPhysicalID); 220 221 TRACE_ALWAYS("%s\titem count: %" B_PRIu32 "\n", indent, fItemCount); 222 for (uint32 i = 0; i < fItemCount; i++) { 223 HIDReportItem *item = fItems[i]; 224 if (item != NULL) 225 item->PrintToStream(indentLevel + 1); 226 } 227 228 TRACE_ALWAYS("%s\tchild count: %" B_PRIu32 "\n", indent, fChildCount); 229 for (uint32 i = 0; i < fChildCount; i++) { 230 HIDCollection *child = fChildren[i]; 231 if (child != NULL) 232 child->PrintToStream(indentLevel + 1); 233 } 234 } 235 236 237 HIDCollection * 238 HIDCollection::_ChildAtFlat(uint8 type, uint32 &index) 239 { 240 if (type == COLLECTION_ALL || fType == type) { 241 if (index == 0) 242 return this; 243 244 index--; 245 } 246 247 for (uint32 i = 0; i < fChildCount; i++) { 248 HIDCollection *child = fChildren[i]; 249 if (child == NULL) 250 continue; 251 252 HIDCollection *result = child->_ChildAtFlat(type, index); 253 if (result != NULL) 254 return result; 255 } 256 257 return NULL; 258 } 259 260 261 HIDReportItem * 262 HIDCollection::_ItemAtFlat(uint32 &index) 263 { 264 if (index < fItemCount) 265 return fItems[index]; 266 267 index -= fItemCount; 268 269 for (uint32 i = 0; i < fChildCount; i++) { 270 HIDCollection *child = fChildren[i]; 271 if (child == NULL) 272 continue; 273 274 HIDReportItem *result = child->_ItemAtFlat(index); 275 if (result != NULL) 276 return result; 277 } 278 279 return NULL; 280 } 281 282 283 void 284 HIDCollection::BuildReportList(uint8 reportType, 285 HIDReport **reportList, uint32 &reportCount) 286 { 287 288 for (uint32 i = 0; i < fItemCount; i++) { 289 HIDReportItem *item = fItems[i]; 290 if (item == NULL) 291 continue; 292 293 HIDReport *report = item->Report(); 294 if (reportType != HID_REPORT_TYPE_ANY && report->Type() != reportType) 295 continue; 296 297 bool found = false; 298 for (uint32 j = 0; j < reportCount; j++) { 299 if (reportList[j] == report) { 300 found = true; 301 break; 302 } 303 } 304 305 if (found) 306 continue; 307 308 reportList[reportCount++] = report; 309 } 310 311 for (uint32 i = 0; i < fChildCount; i++) { 312 HIDCollection *child = fChildren[i]; 313 if (child == NULL) 314 continue; 315 316 child->BuildReportList(reportType, reportList, reportCount); 317 } 318 } 319