* 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
This commit is contained in:
Michael Lotz
2009-05-21 15:53:52 +00:00
parent 9bf61a0ecc
commit 5ba33c51f2
9 changed files with 266 additions and 44 deletions
@@ -5,9 +5,11 @@
#include "Driver.h" #include "Driver.h"
#include "HIDCollection.h" #include "HIDCollection.h"
#include "HIDReportItem.h"
#include <new> #include <new>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
HIDCollection::HIDCollection(HIDCollection *parent, uint8 type, HIDCollection::HIDCollection(HIDCollection *parent, uint8 type,
@@ -17,7 +19,10 @@ HIDCollection::HIDCollection(HIDCollection *parent, uint8 type,
fStringID(localState.string_index), fStringID(localState.string_index),
fPhysicalID(localState.designator_index), fPhysicalID(localState.designator_index),
fChildCount(0), fChildCount(0),
fChildren(NULL) fChildren(NULL),
fItemCount(0),
fItemsAllocated(0),
fItems(NULL)
{ {
usage_value usageValue; usage_value usageValue;
usageValue.u.s.usage_page = globalState.usage_page; usageValue.u.s.usage_page = globalState.usage_page;
@@ -42,6 +47,7 @@ HIDCollection::~HIDCollection()
for (uint32 i = 0; i < fChildCount; i++) for (uint32 i = 0; i < fChildCount; i++)
delete fChildren[i]; delete fChildren[i];
free(fChildren); free(fChildren);
free(fItems);
} }
@@ -72,8 +78,84 @@ HIDCollection::ChildAt(uint32 index)
void void
HIDCollection::AddMainItem(global_item_state &globalState, HIDCollection::AddItem(HIDReportItem *item)
local_item_state &localState, main_item_data &mainData)
{ {
// 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);
}
} }
@@ -7,6 +7,8 @@
#include "HIDParser.h" #include "HIDParser.h"
class HIDReportItem;
class HIDCollection { class HIDCollection {
public: public:
HIDCollection(HIDCollection *parent, HIDCollection(HIDCollection *parent,
@@ -20,9 +22,11 @@ public:
uint32 CountChildren() { return fChildCount; }; uint32 CountChildren() { return fChildCount; };
HIDCollection * ChildAt(uint32 index); HIDCollection * ChildAt(uint32 index);
void AddMainItem(global_item_state &globalState, void AddItem(HIDReportItem *item);
local_item_state &localState, uint32 CountItems() { return fItemCount; };
main_item_data &mainData); HIDReportItem * ItemAt(uint32 index);
void PrintToStream(uint32 indentLevel = 0);
private: private:
HIDCollection * fParent; HIDCollection * fParent;
@@ -34,6 +38,10 @@ private:
uint32 fChildCount; uint32 fChildCount;
HIDCollection ** fChildren; HIDCollection ** fChildren;
uint32 fItemCount;
uint32 fItemsAllocated;
HIDReportItem ** fItems;
}; };
#endif // HID_COLLECTION_H #endif // HID_COLLECTION_H
@@ -124,6 +124,12 @@ typedef struct usage_value {
} u; } u;
bool is_extended; bool is_extended;
usage_value()
{
u.extended = 0;
is_extended = false;
}
} usage_value; } usage_value;
@@ -20,8 +20,9 @@ static int8 sUnitExponent[16] = {
}; };
HIDParser::HIDParser() HIDParser::HIDParser(HIDDevice *device)
: fReportCount(0), : fDevice(device),
fReportCount(0),
fReports(NULL), fReports(NULL),
fRootCollection(NULL) fRootCollection(NULL)
{ {
@@ -35,7 +36,7 @@ HIDParser::~HIDParser()
status_t status_t
HIDParser::ParseReportDescriptor(uint8 *reportDescriptor, HIDParser::ParseReportDescriptor(const uint8 *reportDescriptor,
size_t descriptorLength) size_t descriptorLength)
{ {
_Reset(); _Reset();
@@ -56,11 +57,11 @@ HIDParser::ParseReportDescriptor(uint8 *reportDescriptor,
} }
HIDCollection *collection = NULL; HIDCollection *collection = NULL;
uint8 *pointer = reportDescriptor; const uint8 *pointer = reportDescriptor;
uint8 *end = pointer + descriptorLength; const uint8 *end = pointer + descriptorLength;
while (pointer < end) { while (pointer < end) {
item_prefix *item = (item_prefix *)pointer; const item_prefix *item = (item_prefix *)pointer;
size_t itemSize = sItemSize[item->size]; size_t itemSize = sItemSize[item->size];
uint32 data = 0; uint32 data = 0;
@@ -179,12 +180,8 @@ HIDParser::ParseReportDescriptor(uint8 *reportDescriptor,
if (!localState.string_index_set) if (!localState.string_index_set)
localState.string_index = localState.string_minimum; localState.string_index = localState.string_minimum;
target->AddMainItem(globalState, localState, *mainData); target->AddMainItem(globalState, localState, *mainData,
if (collection != NULL) { collection);
collection->AddMainItem(globalState, localState,
*mainData);
} else
TRACE_ALWAYS("main item not part of a collection\n");
} }
// reset the local item state // reset the local item state
@@ -428,9 +425,40 @@ HIDParser::ReportAt(uint8 type, uint8 index)
} }
status_t size_t
HIDParser::SetReport(uint8 *report, size_t length) 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]; HIDReport *target = fReports[0];
if (fUsesReportIDs) { if (fUsesReportIDs) {
target = FindReport(HID_REPORT_TYPE_INPUT, report[0]); target = FindReport(HID_REPORT_TYPE_INPUT, report[0]);
@@ -440,10 +468,10 @@ HIDParser::SetReport(uint8 *report, size_t length)
if (target == NULL) { if (target == NULL) {
TRACE_ALWAYS("got report buffer but found no report to handle it\n"); 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);
} }
@@ -7,15 +7,19 @@
#include "HIDDataTypes.h" #include "HIDDataTypes.h"
class HIDReport;
class HIDCollection; class HIDCollection;
class HIDDevice;
class HIDReport;
class HIDParser { class HIDParser {
public: public:
HIDParser(); HIDParser(HIDDevice *device);
~HIDParser(); ~HIDParser();
status_t ParseReportDescriptor(uint8 *reportDescriptor, HIDDevice * Device() { return fDevice; };
status_t ParseReportDescriptor(
const uint8 *reportDescriptor,
size_t descriptorLength); size_t descriptorLength);
bool UsesReportIDs() { return fUsesReportIDs; }; bool UsesReportIDs() { return fUsesReportIDs; };
@@ -23,16 +27,19 @@ public:
HIDReport * FindReport(uint8 type, uint8 id); HIDReport * FindReport(uint8 type, uint8 id);
uint8 CountReports(uint8 type); uint8 CountReports(uint8 type);
HIDReport * ReportAt(uint8 type, uint8 index); HIDReport * ReportAt(uint8 type, uint8 index);
size_t MaxReportSize();
HIDCollection * RootCollection() { return fRootCollection; }; HIDCollection * RootCollection() { return fRootCollection; };
status_t SetReport(uint8 *report, size_t length); void SetReport(status_t status, uint8 *report,
size_t length);
private: private:
HIDReport * _FindOrCreateReport(uint8 type, uint8 id); HIDReport * _FindOrCreateReport(uint8 type, uint8 id);
float _CalculateResolution(global_item_state *state); float _CalculateResolution(global_item_state *state);
void _Reset(); void _Reset();
HIDDevice * fDevice;
bool fUsesReportIDs; bool fUsesReportIDs;
uint8 fReportCount; uint8 fReportCount;
HIDReport ** fReports; HIDReport ** fReports;
@@ -4,6 +4,8 @@
*/ */
#include "Driver.h" #include "Driver.h"
#include "HIDCollection.h"
#include "HIDDevice.h"
#include "HIDReport.h" #include "HIDReport.h"
#include "HIDReportItem.h" #include "HIDReportItem.h"
@@ -19,6 +21,7 @@ HIDReport::HIDReport(HIDParser *parser, uint8 type, uint8 id)
fItemsUsed(0), fItemsUsed(0),
fItemsAllocated(0), fItemsAllocated(0),
fItems(NULL), fItems(NULL),
fReportStatus(B_NO_INIT),
fCurrentReport(NULL), fCurrentReport(NULL),
fBusyCount(0) fBusyCount(0)
{ {
@@ -34,7 +37,8 @@ HIDReport::~HIDReport()
void void
HIDReport::AddMainItem(global_item_state &globalState, 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", TRACE("adding main item to report of type 0x%02x with id 0x%02x\n",
fType, fReportID); fType, fReportID);
@@ -121,31 +125,36 @@ HIDReport::AddMainItem(global_item_state &globalState,
usageMinimum = usageMaximum = usage.u.extended; 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, fReportSize, globalState.report_size, mainData.data_constant == 0,
mainData.array_variable == 0, mainData.relative != 0, mainData.array_variable == 0, mainData.relative != 0,
logicalMinimum, logicalMaximum, usageMinimum, usageMaximum); 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 void
HIDReport::SetReport(uint8 *report, size_t length) HIDReport::SetReport(status_t status, uint8 *report, size_t length)
{ {
if (report == NULL) { fReportStatus = status;
fCurrentReport = NULL; fCurrentReport = report;
return B_OK; if (status == B_OK && length * 8 < fReportSize) {
}
if (length * 8 < fReportSize) {
TRACE_ALWAYS("report of %lu bits too small, expected %lu bits\n", TRACE_ALWAYS("report of %lu bits too small, expected %lu bits\n",
length * 8, fReportSize); length * 8, fReportSize);
return B_ERROR; fReportStatus = B_ERROR;
} }
fConditionVariable.NotifyAll(); fConditionVariable.NotifyAll();
fCurrentReport = report;
return B_OK;
} }
@@ -164,18 +173,24 @@ HIDReport::WaitForReport(bigtime_t timeout)
while (atomic_or(&fBusyCount, 0) != 0) while (atomic_or(&fBusyCount, 0) != 0)
snooze(1000); snooze(1000);
#ifndef TEST_MODE
ConditionVariableEntry conditionVariableEntry; ConditionVariableEntry conditionVariableEntry;
fConditionVariable.Add(&conditionVariableEntry); fConditionVariable.Add(&conditionVariableEntry);
//status_t result = fParser->Device()->MaybeScheduleTransfer(); status_t result = fParser->Device()->MaybeScheduleTransfer();
if (result != B_OK) { if (result != B_OK) {
conditionVariableEntry.Wait(B_RELATIVE_TIMEOUT, 0); conditionVariableEntry.Wait(B_RELATIVE_TIMEOUT, 0);
return result; return result;
} }
result = conditionVariableEntry.Wait(B_RELATIVE_TIMEOUT, timeout); result = conditionVariableEntry.Wait(B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT,
timeout);
if (result != B_OK) if (result != B_OK)
return result; return result;
if (fReportStatus != B_OK)
return fReportStatus;
#endif
atomic_add(&fBusyCount, 1); atomic_add(&fBusyCount, 1);
return B_OK; 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 void
HIDReport::_SignExtend(uint32 &minimum, uint32 &maximum) HIDReport::_SignExtend(uint32 &minimum, uint32 &maximum)
{ {
@@ -14,6 +14,7 @@
#define HID_REPORT_TYPE_FEATURE 0x04 #define HID_REPORT_TYPE_FEATURE 0x04
#define HID_REPORT_TYPE_ANY 0x07 #define HID_REPORT_TYPE_ANY 0x07
class HIDCollection;
class HIDReportItem; class HIDReportItem;
class HIDReport { class HIDReport {
@@ -24,12 +25,18 @@ public:
uint8 Type() { return fType; }; uint8 Type() { return fType; };
uint8 ID() { return fReportID; }; 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, void AddMainItem(global_item_state &globalState,
local_item_state &localState, 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; }; uint8 * CurrentReport() { return fCurrentReport; };
uint32 CountItems() { return fItemsUsed; }; uint32 CountItems() { return fItemsUsed; };
@@ -38,6 +45,8 @@ public:
status_t WaitForReport(bigtime_t timeout); status_t WaitForReport(bigtime_t timeout);
void DoneProcessing(); void DoneProcessing();
void PrintToStream();
private: private:
void _SignExtend(uint32 &minimum, uint32 &maximum); void _SignExtend(uint32 &minimum, uint32 &maximum);
@@ -51,6 +60,7 @@ private:
uint32 fItemsAllocated; uint32 fItemsAllocated;
HIDReportItem ** fItems; HIDReportItem ** fItems;
status_t fReportStatus;
uint8 * fCurrentReport; uint8 * fCurrentReport;
int32 fBusyCount; int32 fBusyCount;
ConditionVariable fConditionVariable; ConditionVariable fConditionVariable;
@@ -3,6 +3,8 @@
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#include "Driver.h"
#include "HIDReportItem.h" #include "HIDReportItem.h"
#include "HIDReport.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 status_t
HIDReportItem::Extract() HIDReportItem::Extract()
{ {
@@ -54,3 +65,24 @@ HIDReportItem::Extract()
return B_OK; 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);
}
@@ -22,6 +22,7 @@ public:
bool Array() { return fArray; }; bool Array() { return fArray; };
bool Signed() { return fMinimum > fMaximum; }; bool Signed() { return fMinimum > fMaximum; };
uint16 UsagePage();
uint32 UsageMinimum() { return fUsageMinimum; }; uint32 UsageMinimum() { return fUsageMinimum; };
uint32 UsageMaximum() { return fUsageMaximum; }; uint32 UsageMaximum() { return fUsageMaximum; };
@@ -29,6 +30,7 @@ public:
bool Valid() { return fValid; }; bool Valid() { return fValid; };
uint32 Data() { return fData; }; uint32 Data() { return fData; };
void PrintToStream(uint32 indentLevel = 0);
private: private:
HIDReport * fReport; HIDReport * fReport;
uint32 fByteOffset; uint32 fByteOffset;