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