* 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

View File

@ -5,9 +5,11 @@
#include "Driver.h"
#include "HIDCollection.h"
#include "HIDReportItem.h"
#include <new>
#include <stdlib.h>
#include <string.h>
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);
}
}

View File

@ -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

View File

@ -124,6 +124,12 @@ typedef struct usage_value {
} u;
bool is_extended;
usage_value()
{
u.extended = 0;
is_extended = false;
}
} usage_value;

View File

@ -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);
}

View File

@ -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;

View File

@ -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)
{

View File

@ -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;

View File

@ -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);
}

View File

@ -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;