1aaeffcf7SMichael Lotz/*
2305aff3fSMichael Lotz * Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch.
3aaeffcf7SMichael Lotz * Distributed under the terms of the MIT License.
4aaeffcf7SMichael Lotz */
5aaeffcf7SMichael Lotz
6fd97180eSMichael Lotz#ifndef USERLAND_HID
7e7fcf08dSMichael Lotz#include "Driver.h"
8fd97180eSMichael Lotz#else
9fd97180eSMichael Lotz#include "UserlandHID.h"
10fd97180eSMichael Lotz#endif
11fd97180eSMichael Lotz
12e7fcf08dSMichael Lotz#include "HIDCollection.h"
13305aff3fSMichael Lotz#include "HIDReport.h"
145ba33c51SMichael Lotz#include "HIDReportItem.h"
15e7fcf08dSMichael Lotz
16e7fcf08dSMichael Lotz#include <new>
17e7fcf08dSMichael Lotz#include <stdlib.h>
185ba33c51SMichael Lotz#include <string.h>
19e7fcf08dSMichael Lotz
20e7fcf08dSMichael Lotz
21e7fcf08dSMichael LotzHIDCollection::HIDCollection(HIDCollection *parent, uint8 type,
226e499760SMichael Lotz	local_item_state &localState)
23e7fcf08dSMichael Lotz	:	fParent(parent),
24e7fcf08dSMichael Lotz		fType(type),
25e7fcf08dSMichael Lotz		fStringID(localState.string_index),
26e7fcf08dSMichael Lotz		fPhysicalID(localState.designator_index),
27e7fcf08dSMichael Lotz		fChildCount(0),
285ba33c51SMichael Lotz		fChildren(NULL),
295ba33c51SMichael Lotz		fItemCount(0),
305ba33c51SMichael Lotz		fItemsAllocated(0),
315ba33c51SMichael Lotz		fItems(NULL)
32e7fcf08dSMichael Lotz{
33e7fcf08dSMichael Lotz	usage_value usageValue;
346e499760SMichael Lotz	if (localState.usage_stack != NULL && localState.usage_stack_used > 0)
356e499760SMichael Lotz		usageValue.u.extended = localState.usage_stack[0].u.extended;
366e499760SMichael Lotz	else if (localState.usage_minimum_set)
376e499760SMichael Lotz		usageValue.u.extended = localState.usage_minimum.u.extended;
386e499760SMichael Lotz	else if (localState.usage_maximum_set)
396e499760SMichael Lotz		usageValue.u.extended = localState.usage_maximum.u.extended;
40305aff3fSMichael Lotz	else if (type == COLLECTION_LOGICAL) {
41305aff3fSMichael Lotz		// this is just a logical grouping collection
42305aff3fSMichael Lotz		usageValue.u.extended = 0;
43305aff3fSMichael Lotz	} else {
449a4b557cSMichael Lotz		TRACE_ALWAYS("none of the possible usages for the collection are "
459a4b557cSMichael Lotz			"set\n");
46e7fcf08dSMichael Lotz	}
47e7fcf08dSMichael Lotz
48e7fcf08dSMichael Lotz	fUsage = usageValue.u.extended;
49e7fcf08dSMichael Lotz}
50e7fcf08dSMichael Lotz
51e7fcf08dSMichael Lotz
52e7fcf08dSMichael LotzHIDCollection::~HIDCollection()
53e7fcf08dSMichael Lotz{
54e7fcf08dSMichael Lotz	for (uint32 i = 0; i < fChildCount; i++)
55e7fcf08dSMichael Lotz		delete fChildren[i];
56e7fcf08dSMichael Lotz	free(fChildren);
575ba33c51SMichael Lotz	free(fItems);
58e7fcf08dSMichael Lotz}
59e7fcf08dSMichael Lotz
60e7fcf08dSMichael Lotz
61305aff3fSMichael Lotzuint16
62305aff3fSMichael LotzHIDCollection::UsagePage()
63305aff3fSMichael Lotz{
64305aff3fSMichael Lotz	usage_value value;
65305aff3fSMichael Lotz	value.u.extended = fUsage;
66305aff3fSMichael Lotz	return value.u.s.usage_page;
67305aff3fSMichael Lotz}
68305aff3fSMichael Lotz
69305aff3fSMichael Lotz
70305aff3fSMichael Lotzuint16
71305aff3fSMichael LotzHIDCollection::UsageID()
72305aff3fSMichael Lotz{
73305aff3fSMichael Lotz	usage_value value;
74305aff3fSMichael Lotz	value.u.extended = fUsage;
75305aff3fSMichael Lotz	return value.u.s.usage_id;
76305aff3fSMichael Lotz}
77305aff3fSMichael Lotz
78305aff3fSMichael Lotz
79e7fcf08dSMichael Lotzstatus_t
80e7fcf08dSMichael LotzHIDCollection::AddChild(HIDCollection *child)
81e7fcf08dSMichael Lotz{
82e7fcf08dSMichael Lotz	HIDCollection **newChildren = (HIDCollection **)realloc(fChildren,
83e7fcf08dSMichael Lotz		(fChildCount + 1) * sizeof(HIDCollection *));
84e7fcf08dSMichael Lotz	if (newChildren == NULL) {
85e7fcf08dSMichael Lotz		TRACE_ALWAYS("no memory when trying to resize collection child list\n");
86e7fcf08dSMichael Lotz		return B_NO_MEMORY;
87e7fcf08dSMichael Lotz	}
88e7fcf08dSMichael Lotz
89e7fcf08dSMichael Lotz	fChildren = newChildren;
90e7fcf08dSMichael Lotz	fChildren[fChildCount++] = child;
91e7fcf08dSMichael Lotz	return B_OK;
92e7fcf08dSMichael Lotz}
93e7fcf08dSMichael Lotz
94e7fcf08dSMichael Lotz
95e7fcf08dSMichael LotzHIDCollection *
96e7fcf08dSMichael LotzHIDCollection::ChildAt(uint32 index)
97e7fcf08dSMichael Lotz{
98e7fcf08dSMichael Lotz	if (index >= fChildCount)
99e7fcf08dSMichael Lotz		return NULL;
100e7fcf08dSMichael Lotz
101e7fcf08dSMichael Lotz	return fChildren[index];
102e7fcf08dSMichael Lotz}
103e7fcf08dSMichael Lotz
104e7fcf08dSMichael Lotz
105305aff3fSMichael Lotzuint32
106305aff3fSMichael LotzHIDCollection::CountChildrenFlat(uint8 type)
107305aff3fSMichael Lotz{
108305aff3fSMichael Lotz	uint32 count = 0;
109305aff3fSMichael Lotz	if (type == COLLECTION_ALL || fType == type)
110305aff3fSMichael Lotz		count++;
111305aff3fSMichael Lotz
112305aff3fSMichael Lotz	for (uint32 i = 0; i < fChildCount; i++) {
113305aff3fSMichael Lotz		HIDCollection *child = fChildren[i];
114305aff3fSMichael Lotz		if (child == NULL)
115305aff3fSMichael Lotz			continue;
116305aff3fSMichael Lotz
117305aff3fSMichael Lotz		count += child->CountChildrenFlat(type);
118305aff3fSMichael Lotz	}
119305aff3fSMichael Lotz
120305aff3fSMichael Lotz	return count;
121305aff3fSMichael Lotz}
122305aff3fSMichael Lotz
123305aff3fSMichael Lotz
124305aff3fSMichael LotzHIDCollection *
125305aff3fSMichael LotzHIDCollection::ChildAtFlat(uint8 type, uint32 index)
126305aff3fSMichael Lotz{
127305aff3fSMichael Lotz	return _ChildAtFlat(type, index);
128305aff3fSMichael Lotz}
129305aff3fSMichael Lotz
130305aff3fSMichael Lotz
131e7fcf08dSMichael Lotzvoid
1325ba33c51SMichael LotzHIDCollection::AddItem(HIDReportItem *item)
133e7fcf08dSMichael Lotz{
1345ba33c51SMichael Lotz	if (fItemCount >= fItemsAllocated) {
1355ba33c51SMichael Lotz		fItemsAllocated += 10;
1365ba33c51SMichael Lotz		HIDReportItem **newItems = (HIDReportItem **)realloc(fItems,
1375ba33c51SMichael Lotz			fItemsAllocated * sizeof(HIDReportItem *));
1385ba33c51SMichael Lotz		if (newItems == NULL) {
1395ba33c51SMichael Lotz			TRACE_ALWAYS("no memory when trying to resize collection items\n");
1405ba33c51SMichael Lotz			fItemsAllocated -= 10;
1415ba33c51SMichael Lotz			return;
1425ba33c51SMichael Lotz		}
1435ba33c51SMichael Lotz
1445ba33c51SMichael Lotz		fItems = newItems;
1455ba33c51SMichael Lotz	}
1465ba33c51SMichael Lotz
1475ba33c51SMichael Lotz	fItems[fItemCount++] = item;
1485ba33c51SMichael Lotz}
1495ba33c51SMichael Lotz
1505ba33c51SMichael Lotz
1515ba33c51SMichael LotzHIDReportItem *
1525ba33c51SMichael LotzHIDCollection::ItemAt(uint32 index)
1535ba33c51SMichael Lotz{
1545ba33c51SMichael Lotz	if (index >= fItemCount)
1555ba33c51SMichael Lotz		return NULL;
1565ba33c51SMichael Lotz
1575ba33c51SMichael Lotz	return fItems[index];
1585ba33c51SMichael Lotz}
1595ba33c51SMichael Lotz
1605ba33c51SMichael Lotz
161305aff3fSMichael Lotzuint32
162305aff3fSMichael LotzHIDCollection::CountItemsFlat()
163305aff3fSMichael Lotz{
164305aff3fSMichael Lotz	uint32 count = fItemCount;
165305aff3fSMichael Lotz
166305aff3fSMichael Lotz	for (uint32 i = 0; i < fChildCount; i++) {
167305aff3fSMichael Lotz		HIDCollection *child = fChildren[i];
168305aff3fSMichael Lotz		if (child != NULL)
169305aff3fSMichael Lotz			count += child->CountItemsFlat();
170305aff3fSMichael Lotz	}
171305aff3fSMichael Lotz
172305aff3fSMichael Lotz	return count;
173305aff3fSMichael Lotz}
174305aff3fSMichael Lotz
175305aff3fSMichael Lotz
176305aff3fSMichael LotzHIDReportItem *
177305aff3fSMichael LotzHIDCollection::ItemAtFlat(uint32 index)
178305aff3fSMichael Lotz{
179305aff3fSMichael Lotz	return _ItemAtFlat(index);
180305aff3fSMichael Lotz}
181305aff3fSMichael Lotz
182305aff3fSMichael Lotz
1835ba33c51SMichael Lotzvoid
1845ba33c51SMichael LotzHIDCollection::PrintToStream(uint32 indentLevel)
1855ba33c51SMichael Lotz{
1865ba33c51SMichael Lotz	char indent[indentLevel + 1];
1875ba33c51SMichael Lotz	memset(indent, '\t', indentLevel);
1885ba33c51SMichael Lotz	indent[indentLevel] = 0;
1895ba33c51SMichael Lotz
1905ba33c51SMichael Lotz	const char *typeName = "unknown";
1915ba33c51SMichael Lotz	switch (fType) {
1925ba33c51SMichael Lotz		case COLLECTION_PHYSICAL:
1935ba33c51SMichael Lotz			typeName = "physical";
1945ba33c51SMichael Lotz			break;
1955ba33c51SMichael Lotz		case COLLECTION_APPLICATION:
1965ba33c51SMichael Lotz			typeName = "application";
1975ba33c51SMichael Lotz			break;
1985ba33c51SMichael Lotz		case COLLECTION_LOGICAL:
1995ba33c51SMichael Lotz			typeName = "logical";
2005ba33c51SMichael Lotz			break;
2015ba33c51SMichael Lotz		case COLLECTION_REPORT:
2025ba33c51SMichael Lotz			typeName = "report";
2035ba33c51SMichael Lotz			break;
2045ba33c51SMichael Lotz		case COLLECTION_NAMED_ARRAY:
2055ba33c51SMichael Lotz			typeName = "named array";
2065ba33c51SMichael Lotz			break;
2075ba33c51SMichael Lotz		case COLLECTION_USAGE_SWITCH:
2085ba33c51SMichael Lotz			typeName = "usage switch";
2095ba33c51SMichael Lotz			break;
2105ba33c51SMichael Lotz		case COLLECTION_USAGE_MODIFIER:
2115ba33c51SMichael Lotz			typeName = "usage modifier";
2125ba33c51SMichael Lotz			break;
2135ba33c51SMichael Lotz	}
2145ba33c51SMichael Lotz
2155ba33c51SMichael Lotz	TRACE_ALWAYS("%sHIDCollection %p\n", indent, this);
2165ba33c51SMichael Lotz	TRACE_ALWAYS("%s\ttype: %u %s\n", indent, fType, typeName);
2177e5b39b6SAlex Smith	TRACE_ALWAYS("%s\tusage: 0x%08" B_PRIx32 "\n", indent, fUsage);
2185ba33c51SMichael Lotz	TRACE_ALWAYS("%s\tstring id: %u\n", indent, fStringID);
2195ba33c51SMichael Lotz	TRACE_ALWAYS("%s\tphysical id: %u\n", indent, fPhysicalID);
2205ba33c51SMichael Lotz
2217e5b39b6SAlex Smith	TRACE_ALWAYS("%s\titem count: %" B_PRIu32 "\n", indent, fItemCount);
2225ba33c51SMichael Lotz	for (uint32 i = 0; i < fItemCount; i++) {
2235ba33c51SMichael Lotz		HIDReportItem *item = fItems[i];
2245ba33c51SMichael Lotz		if (item != NULL)
2255ba33c51SMichael Lotz			item->PrintToStream(indentLevel + 1);
2265ba33c51SMichael Lotz	}
2275ba33c51SMichael Lotz
2287e5b39b6SAlex Smith	TRACE_ALWAYS("%s\tchild count: %" B_PRIu32 "\n", indent, fChildCount);
2295ba33c51SMichael Lotz	for (uint32 i = 0; i < fChildCount; i++) {
2305ba33c51SMichael Lotz		HIDCollection *child = fChildren[i];
2315ba33c51SMichael Lotz		if (child != NULL)
2325ba33c51SMichael Lotz			child->PrintToStream(indentLevel + 1);
2335ba33c51SMichael Lotz	}
234e7fcf08dSMichael Lotz}
235305aff3fSMichael Lotz
236305aff3fSMichael Lotz
237305aff3fSMichael LotzHIDCollection *
238305aff3fSMichael LotzHIDCollection::_ChildAtFlat(uint8 type, uint32 &index)
239305aff3fSMichael Lotz{
240305aff3fSMichael Lotz	if (type == COLLECTION_ALL || fType == type) {
241305aff3fSMichael Lotz		if (index == 0)
242305aff3fSMichael Lotz			return this;
243305aff3fSMichael Lotz
244305aff3fSMichael Lotz		index--;
245305aff3fSMichael Lotz	}
246305aff3fSMichael Lotz
247305aff3fSMichael Lotz	for (uint32 i = 0; i < fChildCount; i++) {
248305aff3fSMichael Lotz		HIDCollection *child = fChildren[i];
249305aff3fSMichael Lotz		if (child == NULL)
250305aff3fSMichael Lotz			continue;
251305aff3fSMichael Lotz
252305aff3fSMichael Lotz		HIDCollection *result = child->_ChildAtFlat(type, index);
253305aff3fSMichael Lotz		if (result != NULL)
254305aff3fSMichael Lotz			return result;
255305aff3fSMichael Lotz	}
256305aff3fSMichael Lotz
257305aff3fSMichael Lotz	return NULL;
258305aff3fSMichael Lotz}
259305aff3fSMichael Lotz
260305aff3fSMichael Lotz
261305aff3fSMichael LotzHIDReportItem *
262305aff3fSMichael LotzHIDCollection::_ItemAtFlat(uint32 &index)
263305aff3fSMichael Lotz{
264305aff3fSMichael Lotz	if (index < fItemCount)
265305aff3fSMichael Lotz		return fItems[index];
266305aff3fSMichael Lotz
267305aff3fSMichael Lotz	index -= fItemCount;
268305aff3fSMichael Lotz
269305aff3fSMichael Lotz	for (uint32 i = 0; i < fChildCount; i++) {
270305aff3fSMichael Lotz		HIDCollection *child = fChildren[i];
271305aff3fSMichael Lotz		if (child == NULL)
272305aff3fSMichael Lotz			continue;
273305aff3fSMichael Lotz
274305aff3fSMichael Lotz		HIDReportItem *result = child->_ItemAtFlat(index);
275305aff3fSMichael Lotz		if (result != NULL)
276305aff3fSMichael Lotz			return result;
277305aff3fSMichael Lotz	}
278305aff3fSMichael Lotz