* 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:
parent
9bf61a0ecc
commit
5ba33c51f2
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -124,6 +124,12 @@ typedef struct usage_value {
|
||||
} u;
|
||||
|
||||
bool is_extended;
|
||||
|
||||
usage_value()
|
||||
{
|
||||
u.extended = 0;
|
||||
is_extended = false;
|
||||
}
|
||||
} usage_value;
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user