From 5ba33c51f2ce94cddeed22b796bac9123cf296a9 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Thu, 21 May 2009 15:53:52 +0000 Subject: [PATCH] * Integrate reports/items some more. * Reorganize how items are added to collections. * Make collections useful for enumeration through that. * Added printing out of collections, reports and report items for easier verification of report parsing. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30821 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../drivers/input/usb_hid/HIDCollection.cpp | 90 ++++++++++++++++++- .../drivers/input/usb_hid/HIDCollection.h | 14 ++- .../drivers/input/usb_hid/HIDDataTypes.h | 6 ++ .../drivers/input/usb_hid/HIDParser.cpp | 60 +++++++++---- .../kernel/drivers/input/usb_hid/HIDParser.h | 15 +++- .../drivers/input/usb_hid/HIDReport.cpp | 77 ++++++++++++---- .../kernel/drivers/input/usb_hid/HIDReport.h | 14 ++- .../drivers/input/usb_hid/HIDReportItem.cpp | 32 +++++++ .../drivers/input/usb_hid/HIDReportItem.h | 2 + 9 files changed, 266 insertions(+), 44 deletions(-) diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.cpp b/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.cpp index e4b3d6f1b7..4bdde2297b 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.cpp @@ -5,9 +5,11 @@ #include "Driver.h" #include "HIDCollection.h" +#include "HIDReportItem.h" #include #include +#include HIDCollection::HIDCollection(HIDCollection *parent, uint8 type, @@ -17,7 +19,10 @@ HIDCollection::HIDCollection(HIDCollection *parent, uint8 type, fStringID(localState.string_index), fPhysicalID(localState.designator_index), fChildCount(0), - fChildren(NULL) + fChildren(NULL), + fItemCount(0), + fItemsAllocated(0), + fItems(NULL) { usage_value usageValue; usageValue.u.s.usage_page = globalState.usage_page; @@ -42,6 +47,7 @@ HIDCollection::~HIDCollection() for (uint32 i = 0; i < fChildCount; i++) delete fChildren[i]; free(fChildren); + free(fItems); } @@ -72,8 +78,84 @@ HIDCollection::ChildAt(uint32 index) void -HIDCollection::AddMainItem(global_item_state &globalState, - local_item_state &localState, main_item_data &mainData) +HIDCollection::AddItem(HIDReportItem *item) { - // TODO: implement + if (fItemCount >= fItemsAllocated) { + fItemsAllocated += 10; + HIDReportItem **newItems = (HIDReportItem **)realloc(fItems, + fItemsAllocated * sizeof(HIDReportItem *)); + if (newItems == NULL) { + TRACE_ALWAYS("no memory when trying to resize collection items\n"); + fItemsAllocated -= 10; + return; + } + + fItems = newItems; + } + + fItems[fItemCount++] = item; +} + + +HIDReportItem * +HIDCollection::ItemAt(uint32 index) +{ + if (index >= fItemCount) + return NULL; + + return fItems[index]; +} + + +void +HIDCollection::PrintToStream(uint32 indentLevel) +{ + char indent[indentLevel + 1]; + memset(indent, '\t', indentLevel); + indent[indentLevel] = 0; + + const char *typeName = "unknown"; + switch (fType) { + case COLLECTION_PHYSICAL: + typeName = "physical"; + break; + case COLLECTION_APPLICATION: + typeName = "application"; + break; + case COLLECTION_LOGICAL: + typeName = "logical"; + break; + case COLLECTION_REPORT: + typeName = "report"; + break; + case COLLECTION_NAMED_ARRAY: + typeName = "named array"; + break; + case COLLECTION_USAGE_SWITCH: + typeName = "usage switch"; + break; + case COLLECTION_USAGE_MODIFIER: + typeName = "usage modifier"; + break; + } + + TRACE_ALWAYS("%sHIDCollection %p\n", indent, this); + TRACE_ALWAYS("%s\ttype: %u %s\n", indent, fType, typeName); + TRACE_ALWAYS("%s\tusage: 0x%08lx\n", indent, fUsage); + TRACE_ALWAYS("%s\tstring id: %u\n", indent, fStringID); + TRACE_ALWAYS("%s\tphysical id: %u\n", indent, fPhysicalID); + + TRACE_ALWAYS("%s\titem count: %lu\n", indent, fItemCount); + for (uint32 i = 0; i < fItemCount; i++) { + HIDReportItem *item = fItems[i]; + if (item != NULL) + item->PrintToStream(indentLevel + 1); + } + + TRACE_ALWAYS("%s\tchild count: %lu\n", indent, fChildCount); + for (uint32 i = 0; i < fChildCount; i++) { + HIDCollection *child = fChildren[i]; + if (child != NULL) + child->PrintToStream(indentLevel + 1); + } } diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.h b/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.h index 6763c6fbdf..badef89fa8 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.h @@ -7,6 +7,8 @@ #include "HIDParser.h" +class HIDReportItem; + class HIDCollection { public: HIDCollection(HIDCollection *parent, @@ -20,9 +22,11 @@ public: uint32 CountChildren() { return fChildCount; }; HIDCollection * ChildAt(uint32 index); - void AddMainItem(global_item_state &globalState, - local_item_state &localState, - main_item_data &mainData); + void AddItem(HIDReportItem *item); + uint32 CountItems() { return fItemCount; }; + HIDReportItem * ItemAt(uint32 index); + + void PrintToStream(uint32 indentLevel = 0); private: HIDCollection * fParent; @@ -34,6 +38,10 @@ private: uint32 fChildCount; HIDCollection ** fChildren; + + uint32 fItemCount; + uint32 fItemsAllocated; + HIDReportItem ** fItems; }; #endif // HID_COLLECTION_H diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDDataTypes.h b/src/add-ons/kernel/drivers/input/usb_hid/HIDDataTypes.h index a86a898477..f847ebb0c2 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDDataTypes.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDDataTypes.h @@ -124,6 +124,12 @@ typedef struct usage_value { } u; bool is_extended; + + usage_value() + { + u.extended = 0; + is_extended = false; + } } usage_value; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDParser.cpp b/src/add-ons/kernel/drivers/input/usb_hid/HIDParser.cpp index 2c39140182..fcc65f0c06 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDParser.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDParser.cpp @@ -20,8 +20,9 @@ static int8 sUnitExponent[16] = { }; -HIDParser::HIDParser() - : fReportCount(0), +HIDParser::HIDParser(HIDDevice *device) + : fDevice(device), + fReportCount(0), fReports(NULL), fRootCollection(NULL) { @@ -35,7 +36,7 @@ HIDParser::~HIDParser() status_t -HIDParser::ParseReportDescriptor(uint8 *reportDescriptor, +HIDParser::ParseReportDescriptor(const uint8 *reportDescriptor, size_t descriptorLength) { _Reset(); @@ -56,11 +57,11 @@ HIDParser::ParseReportDescriptor(uint8 *reportDescriptor, } HIDCollection *collection = NULL; - uint8 *pointer = reportDescriptor; - uint8 *end = pointer + descriptorLength; + const uint8 *pointer = reportDescriptor; + const uint8 *end = pointer + descriptorLength; while (pointer < end) { - item_prefix *item = (item_prefix *)pointer; + const item_prefix *item = (item_prefix *)pointer; size_t itemSize = sItemSize[item->size]; uint32 data = 0; @@ -179,12 +180,8 @@ HIDParser::ParseReportDescriptor(uint8 *reportDescriptor, if (!localState.string_index_set) localState.string_index = localState.string_minimum; - target->AddMainItem(globalState, localState, *mainData); - if (collection != NULL) { - collection->AddMainItem(globalState, localState, - *mainData); - } else - TRACE_ALWAYS("main item not part of a collection\n"); + target->AddMainItem(globalState, localState, *mainData, + collection); } // reset the local item state @@ -428,9 +425,40 @@ HIDParser::ReportAt(uint8 type, uint8 index) } -status_t -HIDParser::SetReport(uint8 *report, size_t length) +size_t +HIDParser::MaxReportSize() { + size_t maxSize = 0; + for (uint32 i = 0; i < fReportCount; i++) { + HIDReport *report = fReports[i]; + if (report == NULL) + continue; + + if (report->ReportSize() > maxSize) + maxSize = report->ReportSize(); + } + + return maxSize; +} + + +void +HIDParser::SetReport(status_t status, uint8 *report, size_t length) +{ + if (status != B_OK) { + // in case of error we need to notify all input reports, as we don't + // know who has waiting listeners. + for (uint32 i = 0; i < fReportCount; i++) { + if (fReports[i] == NULL + || fReports[i]->Type() != HID_REPORT_TYPE_INPUT) + continue; + + fReports[i]->SetReport(status, NULL, 0); + } + + return; + } + HIDReport *target = fReports[0]; if (fUsesReportIDs) { target = FindReport(HID_REPORT_TYPE_INPUT, report[0]); @@ -440,10 +468,10 @@ HIDParser::SetReport(uint8 *report, size_t length) if (target == NULL) { TRACE_ALWAYS("got report buffer but found no report to handle it\n"); - return B_ENTRY_NOT_FOUND; + return; } - return target->SetReport(report, length); + target->SetReport(status, report, length); } diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDParser.h b/src/add-ons/kernel/drivers/input/usb_hid/HIDParser.h index 642c48174e..54a93fe136 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDParser.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDParser.h @@ -7,15 +7,19 @@ #include "HIDDataTypes.h" -class HIDReport; class HIDCollection; +class HIDDevice; +class HIDReport; class HIDParser { public: - HIDParser(); + HIDParser(HIDDevice *device); ~HIDParser(); - status_t ParseReportDescriptor(uint8 *reportDescriptor, + HIDDevice * Device() { return fDevice; }; + + status_t ParseReportDescriptor( + const uint8 *reportDescriptor, size_t descriptorLength); bool UsesReportIDs() { return fUsesReportIDs; }; @@ -23,16 +27,19 @@ public: HIDReport * FindReport(uint8 type, uint8 id); uint8 CountReports(uint8 type); HIDReport * ReportAt(uint8 type, uint8 index); + size_t MaxReportSize(); HIDCollection * RootCollection() { return fRootCollection; }; - status_t SetReport(uint8 *report, size_t length); + void SetReport(status_t status, uint8 *report, + size_t length); private: HIDReport * _FindOrCreateReport(uint8 type, uint8 id); float _CalculateResolution(global_item_state *state); void _Reset(); + HIDDevice * fDevice; bool fUsesReportIDs; uint8 fReportCount; HIDReport ** fReports; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.cpp b/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.cpp index a627f68ec3..c4f24dd4a5 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.cpp @@ -4,6 +4,8 @@ */ #include "Driver.h" +#include "HIDCollection.h" +#include "HIDDevice.h" #include "HIDReport.h" #include "HIDReportItem.h" @@ -19,6 +21,7 @@ HIDReport::HIDReport(HIDParser *parser, uint8 type, uint8 id) fItemsUsed(0), fItemsAllocated(0), fItems(NULL), + fReportStatus(B_NO_INIT), fCurrentReport(NULL), fBusyCount(0) { @@ -34,7 +37,8 @@ HIDReport::~HIDReport() void HIDReport::AddMainItem(global_item_state &globalState, - local_item_state &localState, main_item_data &mainData) + local_item_state &localState, main_item_data &mainData, + HIDCollection *collection) { TRACE("adding main item to report of type 0x%02x with id 0x%02x\n", fType, fReportID); @@ -121,31 +125,36 @@ HIDReport::AddMainItem(global_item_state &globalState, usageMinimum = usageMaximum = usage.u.extended; } - fItems[fItemsUsed++] = new(std::nothrow) HIDReportItem(this, + fItems[fItemsUsed] = new(std::nothrow) HIDReportItem(this, fReportSize, globalState.report_size, mainData.data_constant == 0, mainData.array_variable == 0, mainData.relative != 0, logicalMinimum, logicalMaximum, usageMinimum, usageMaximum); + if (fItems[fItemsUsed] == NULL) + TRACE_ALWAYS("no memory when creating report item\n"); + + if (collection != NULL) + collection->AddItem(fItems[fItemsUsed]); + else + TRACE_ALWAYS("main item not part of a collection\n"); + + fReportSize += globalState.report_size; + fItemsUsed++; } } -status_t -HIDReport::SetReport(uint8 *report, size_t length) +void +HIDReport::SetReport(status_t status, uint8 *report, size_t length) { - if (report == NULL) { - fCurrentReport = NULL; - return B_OK; - } - - if (length * 8 < fReportSize) { + fReportStatus = status; + fCurrentReport = report; + if (status == B_OK && length * 8 < fReportSize) { TRACE_ALWAYS("report of %lu bits too small, expected %lu bits\n", length * 8, fReportSize); - return B_ERROR; + fReportStatus = B_ERROR; } fConditionVariable.NotifyAll(); - fCurrentReport = report; - return B_OK; } @@ -164,18 +173,24 @@ HIDReport::WaitForReport(bigtime_t timeout) while (atomic_or(&fBusyCount, 0) != 0) snooze(1000); +#ifndef TEST_MODE ConditionVariableEntry conditionVariableEntry; fConditionVariable.Add(&conditionVariableEntry); - //status_t result = fParser->Device()->MaybeScheduleTransfer(); + status_t result = fParser->Device()->MaybeScheduleTransfer(); if (result != B_OK) { conditionVariableEntry.Wait(B_RELATIVE_TIMEOUT, 0); return result; } - result = conditionVariableEntry.Wait(B_RELATIVE_TIMEOUT, timeout); + result = conditionVariableEntry.Wait(B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, + timeout); if (result != B_OK) return result; + if (fReportStatus != B_OK) + return fReportStatus; +#endif + atomic_add(&fBusyCount, 1); return B_OK; } @@ -188,6 +203,38 @@ HIDReport::DoneProcessing() } +void +HIDReport::PrintToStream() +{ + TRACE_ALWAYS("HIDReport %p\n", this); + + const char *typeName = "unknown"; + switch (fType) { + case HID_REPORT_TYPE_INPUT: + typeName = "input"; + break; + case HID_REPORT_TYPE_OUTPUT: + typeName = "output"; + break; + case HID_REPORT_TYPE_FEATURE: + typeName = "feature"; + break; + } + + TRACE_ALWAYS("\ttype: %u %s\n", fType, typeName); + TRACE_ALWAYS("\treport id: %u\n", fReportID); + TRACE_ALWAYS("\treport size: %lu bits = %lu bytes\n", fReportSize, + (fReportSize + 7) / 8); + + TRACE_ALWAYS("\titem count: %lu\n", fItemsUsed); + for (uint32 i = 0; i < fItemsUsed; i++) { + HIDReportItem *item = fItems[i]; + if (item != NULL) + item->PrintToStream(1); + } +} + + void HIDReport::_SignExtend(uint32 &minimum, uint32 &maximum) { diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.h b/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.h index c030c67a4d..e760b9f607 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.h @@ -14,6 +14,7 @@ #define HID_REPORT_TYPE_FEATURE 0x04 #define HID_REPORT_TYPE_ANY 0x07 +class HIDCollection; class HIDReportItem; class HIDReport { @@ -24,12 +25,18 @@ public: uint8 Type() { return fType; }; uint8 ID() { return fReportID; }; + size_t ReportSize() { return (fReportSize + 7) / 8; }; + + HIDParser * Parser() { return fParser; }; + HIDDevice * Device() { return fParser->Device(); }; void AddMainItem(global_item_state &globalState, local_item_state &localState, - main_item_data &mainData); + main_item_data &mainData, + HIDCollection *collection); - status_t SetReport(uint8 *report, size_t length); + void SetReport(status_t status, uint8 *report, + size_t length); uint8 * CurrentReport() { return fCurrentReport; }; uint32 CountItems() { return fItemsUsed; }; @@ -38,6 +45,8 @@ public: status_t WaitForReport(bigtime_t timeout); void DoneProcessing(); + void PrintToStream(); + private: void _SignExtend(uint32 &minimum, uint32 &maximum); @@ -51,6 +60,7 @@ private: uint32 fItemsAllocated; HIDReportItem ** fItems; + status_t fReportStatus; uint8 * fCurrentReport; int32 fBusyCount; ConditionVariable fConditionVariable; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.cpp b/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.cpp index 2dbf811173..9341efbf46 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.cpp @@ -3,6 +3,8 @@ * Distributed under the terms of the MIT License. */ +#include "Driver.h" + #include "HIDReportItem.h" #include "HIDReport.h" @@ -28,6 +30,15 @@ HIDReportItem::HIDReportItem(HIDReport *report, uint32 bitOffset, } +uint16 +HIDReportItem::UsagePage() +{ + usage_value value; + value.u.extended = fUsageMinimum; + return value.u.s.usage_page; +} + + status_t HIDReportItem::Extract() { @@ -54,3 +65,24 @@ HIDReportItem::Extract() return B_OK; } + + +void +HIDReportItem::PrintToStream(uint32 indentLevel) +{ + char indent[indentLevel + 1]; + memset(indent, '\t', indentLevel); + indent[indentLevel] = 0; + + TRACE_ALWAYS("%sHIDReportItem %p\n", indent, this); + TRACE_ALWAYS("%s\tbyte offset: %lu\n", indent, fByteOffset); + TRACE_ALWAYS("%s\tshift: %u\n", indent, fShift); + TRACE_ALWAYS("%s\tmask: 0x%08lx\n", indent, fMask); + TRACE_ALWAYS("%s\thas data: %s\n", indent, fHasData ? "yes" : "no"); + TRACE_ALWAYS("%s\tarray: %s\n", indent, fArray ? "yes" : "no"); + TRACE_ALWAYS("%s\trelative: %s\n", indent, fRelative ? "yes" : "no"); + TRACE_ALWAYS("%s\tminimum: %lu\n", indent, fMinimum); + TRACE_ALWAYS("%s\tmaximum: %lu\n", indent, fMaximum); + TRACE_ALWAYS("%s\tusage minimum: 0x%08lx\n", indent, fUsageMinimum); + TRACE_ALWAYS("%s\tusage maximum: 0x%08lx\n", indent, fUsageMaximum); +} diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.h b/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.h index b8ab3c030d..b5ebfac3a1 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.h @@ -22,6 +22,7 @@ public: bool Array() { return fArray; }; bool Signed() { return fMinimum > fMaximum; }; + uint16 UsagePage(); uint32 UsageMinimum() { return fUsageMinimum; }; uint32 UsageMaximum() { return fUsageMaximum; }; @@ -29,6 +30,7 @@ public: bool Valid() { return fValid; }; uint32 Data() { return fData; }; + void PrintToStream(uint32 indentLevel = 0); private: HIDReport * fReport; uint32 fByteOffset;