1 /* 2 * Copyright 2009, 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 "HIDDevice.h" 14 #include "HIDReport.h" 15 #include "HIDReportItem.h" 16 17 #include <new> 18 #include <stdlib.h> 19 #include <string.h> 20 21 22 HIDReport::HIDReport(HIDParser *parser, uint8 type, uint8 id) 23 : fParser(parser), 24 fType(type), 25 fReportID(id), 26 fReportSize(0), 27 fReportStatus(B_NO_INIT), 28 fCurrentReport(NULL), 29 fBusyCount(0) 30 { 31 #ifndef USERLAND_HID 32 fConditionVariable.Init(this, "hid report"); 33 #endif 34 } 35 36 37 HIDReport::~HIDReport() 38 { 39 } 40 41 42 void 43 HIDReport::AddMainItem(global_item_state &globalState, 44 local_item_state &localState, main_item_data &mainData, 45 HIDCollection *collection) 46 { 47 TRACE("adding main item to report of type 0x%02x with id 0x%02x\n", 48 fType, fReportID); 49 TRACE("\tmain data:\n"); 50 TRACE("\t\t%s\n", mainData.data_constant ? "constant" : "data"); 51 TRACE("\t\t%s\n", mainData.array_variable ? "variable" : "array"); 52 TRACE("\t\t%s\n", mainData.relative ? "relative" : "absolute"); 53 TRACE("\t\t%swrap\n", mainData.wrap ? "" : "no-"); 54 TRACE("\t\t%slinear\n", mainData.non_linear ? "non-" : ""); 55 TRACE("\t\t%spreferred state\n", mainData.no_preferred ? "no " : ""); 56 TRACE("\t\t%s null\n", mainData.null_state ? "has" : "no"); 57 TRACE("\t\t%svolatile\n", mainData.is_volatile ? "" : "non-"); 58 TRACE("\t\t%s\n", mainData.bits_bytes ? "bit array" : "buffered bytes"); 59 60 uint32 logicalMinimum = globalState.logical_minimum; 61 uint32 logicalMaximum = globalState.logical_maximum; 62 if (logicalMinimum > logicalMaximum) 63 _SignExtend(logicalMinimum, logicalMaximum); 64 65 uint32 physicalMinimum = globalState.physical_minimum; 66 uint32 physicalMaximum = globalState.physical_maximum; 67 if (physicalMinimum > physicalMaximum) 68 _SignExtend(physicalMinimum, physicalMaximum); 69 70 TRACE("\tglobal state:\n"); 71 TRACE("\t\tusage_page: 0x%x\n", globalState.usage_page); 72 TRACE("\t\tlogical_minimum: %" B_PRId32 "\n", logicalMinimum); 73 TRACE("\t\tlogical_maximum: %" B_PRId32 "\n", logicalMaximum); 74 TRACE("\t\tphysical_minimum: %" B_PRId32 "\n", physicalMinimum); 75 TRACE("\t\tphysical_maximum: %" B_PRId32 "\n", physicalMaximum); 76 TRACE("\t\tunit_exponent: %d\n", globalState.unit_exponent); 77 TRACE("\t\tunit: %d\n", globalState.unit); 78 TRACE("\t\treport_size: %" B_PRIu32 "\n", globalState.report_size); 79 TRACE("\t\treport_count: %" B_PRIu32 "\n", globalState.report_count); 80 TRACE("\t\treport_id: %u\n", globalState.report_id); 81 82 TRACE("\tlocal state:\n"); 83 TRACE("\t\tusage stack (%" B_PRIu32 ")\n", localState.usage_stack_used); 84 for (uint32 i = 0; i < localState.usage_stack_used; i++) { 85 TRACE("\t\t\t0x%08" B_PRIx32 "\n", 86 localState.usage_stack[i].u.extended); 87 } 88 89 TRACE("\t\tusage_minimum: 0x%08" B_PRIx32 "\n", 90 localState.usage_minimum.u.extended); 91 TRACE("\t\tusage_maximum: 0x%08" B_PRIu32 "\n", 92 localState.usage_maximum.u.extended); 93 TRACE("\t\tdesignator_index: %" B_PRIu32 "\n", 94 localState.designator_index); 95 TRACE("\t\tdesignator_minimum: %" B_PRIu32 "\n", 96 localState.designator_minimum); 97 TRACE("\t\tdesignator_maximum: %" B_PRIu32 "\n", 98 localState.designator_maximum); 99 TRACE("\t\tstring_index: %u\n", localState.string_index); 100 TRACE("\t\tstring_minimum: %u\n", localState.string_minimum); 101 TRACE("\t\tstring_maximum: %u\n", localState.string_maximum); 102 103 for (uint32 n = 0; n <localState.usage_stack_used; n++) { 104 if (fUsages.PushBack(localState.usage_stack[n].u.extended) != B_OK) { 105 TRACE_ALWAYS("no memory allocating usages\n"); 106 break; 107 } 108 } 109 110 usage_value page; 111 112 if (localState.usage_stack_used > 0) { 113 page = localState.usage_stack[0]; 114 page.u.s.usage_id = 0; 115 } 116 117 uint32 usage = page.u.extended; 118 119 for (uint32 i = 0; i < globalState.report_count; i++) { 120 if (mainData.array_variable == 1) { 121 122 if (i < localState.usage_stack_used) 123 usage = localState.usage_stack[i].u.extended; 124 } 125 126 HIDReportItem *item = new(std::nothrow) HIDReportItem(this, 127 fReportSize, globalState.report_size, mainData.data_constant == 0, 128 mainData.array_variable == 0, mainData.relative != 0, 129 logicalMinimum, logicalMaximum, usage); 130 if (item == NULL) 131 TRACE_ALWAYS("no memory when creating report item\n"); 132 133 if (collection != NULL) 134 collection->AddItem(item); 135 else 136 TRACE_ALWAYS("main item not part of a collection\n"); 137 138 if (fItems.PushBack(item) == B_NO_MEMORY) { 139 TRACE_ALWAYS("no memory when growing report item list\n"); 140 } 141 142 fReportSize += globalState.report_size; 143 } 144 145 } 146 147 148 void 149 HIDReport::SetReport(status_t status, uint8 *report, size_t length) 150 { 151 fReportStatus = status; 152 fCurrentReport = report; 153 if (status == B_OK && length * 8 < fReportSize) { 154 TRACE_ALWAYS("report of %lu bits too small, expected %" B_PRIu32 155 " bits\n", length * 8, fReportSize); 156 fReportStatus = B_ERROR; 157 } 158 159 #ifndef USERLAND_HID 160 fConditionVariable.NotifyAll(); 161 #endif 162 } 163 164 165 #ifndef USERLAND_HID 166 status_t 167 HIDReport::SendReport() 168 { 169 size_t reportSize = ReportSize(); 170 uint8 *report = (uint8 *)malloc(reportSize); 171 if (report == NULL) 172 return B_NO_MEMORY; 173 174 fCurrentReport = report; 175 memset(fCurrentReport, 0, reportSize); 176 177 for (int32 i = 0; i < fItems.Count(); i++) { 178 HIDReportItem *item = fItems[i]; 179 if (item == NULL) 180 continue; 181 182 item->Insert(); 183 } 184 185 status_t result = fParser->Device()->SendReport(this); 186 187 fCurrentReport = NULL; 188 free(report); 189 return result; 190 } 191 #endif // !USERLAND_HID 192 193 194 HIDReportItem * 195 HIDReport::ItemAt(uint32 index) 196 { 197 if (index >= fItems.Count()) 198 return NULL; 199 return fItems[index]; 200 } 201 202 203 HIDReportItem * 204 HIDReport::FindItem(uint16 usagePage, uint16 usageID) 205 { 206 for (int32 i = 0; i < fItems.Count(); i++) { 207 if (fItems[i]->UsagePage() == usagePage 208 && fItems[i]->UsageID() == usageID) 209 return fItems[i]; 210 } 211 212 return NULL; 213 } 214 215 216 uint32 * 217 HIDReport::Usages() 218 { 219 if (fUsages.Count() > 0) 220 return &fUsages[0]; 221 222 return NULL; 223 } 224 225 226 #ifndef USERLAND_HID 227 status_t 228 HIDReport::WaitForReport(bigtime_t timeout) 229 { 230 while (atomic_get(&fBusyCount) != 0) 231 snooze(1000); 232 233 ConditionVariableEntry conditionVariableEntry; 234 fConditionVariable.Add(&conditionVariableEntry); 235 status_t result = fParser->Device()->MaybeScheduleTransfer(this); 236 if (result != B_OK) { 237 TRACE_ALWAYS("scheduling transfer failed\n"); 238 conditionVariableEntry.Wait(B_RELATIVE_TIMEOUT, 0); 239 return result; 240 } 241 242 result = conditionVariableEntry.Wait(B_RELATIVE_TIMEOUT, timeout); 243 TRACE("waiting for report returned with result: %s\n", strerror(result)); 244 if (result != B_OK) 245 return result; 246 247 if (fReportStatus != B_OK) 248 return fReportStatus; 249 250 atomic_add(&fBusyCount, 1); 251 return B_OK; 252 } 253 254 255 void 256 HIDReport::DoneProcessing() 257 { 258 atomic_add(&fBusyCount, -1); 259 } 260 #endif // !USERLAND_HID 261 262 263 void 264 HIDReport::PrintToStream() 265 { 266 TRACE_ALWAYS("HIDReport %p\n", this); 267 268 const char *typeName = "unknown"; 269 switch (fType) { 270 case HID_REPORT_TYPE_INPUT: 271 typeName = "input"; 272 break; 273 case HID_REPORT_TYPE_OUTPUT: 274 typeName = "output"; 275 break; 276 case HID_REPORT_TYPE_FEATURE: 277 typeName = "feature"; 278 break; 279 } 280 281 TRACE_ALWAYS("\ttype: %u %s\n", fType, typeName); 282 TRACE_ALWAYS("\treport id: %u\n", fReportID); 283 TRACE_ALWAYS("\treport size: %" B_PRIu32 " bits = %" B_PRIu32 " bytes\n", 284 fReportSize, (fReportSize + 7) / 8); 285 286 TRACE_ALWAYS("\titem count: %" B_PRIu32 "\n", fItems.Count()); 287 for (int32 i = 0; i < fItems.Count(); i++) { 288 HIDReportItem *item = fItems[i]; 289 if (item != NULL) 290 item->PrintToStream(1); 291 } 292 } 293 294 295 void 296 HIDReport::_SignExtend(uint32 &minimum, uint32 &maximum) 297 { 298 uint32 mask = 0x80000000; 299 for (uint8 i = 0; i < 4; i++) { 300 if (minimum & mask) { 301 minimum |= mask; 302 if (maximum & mask) 303 maximum |= mask; 304 return; 305 } 306 307 mask >>= 8; 308 mask |= 0xff000000; 309 } 310 } 311