1/*
2 * Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch.
3 * Distributed under the terms of the MIT License.
4 */
5
6#ifndef USERLAND_HID
7#include "Driver.h"
8#else
9#include "UserlandHID.h"
10#endif
11
12#include "HIDCollection.h"
13#include "HIDReport.h"
14#include "HIDReportItem.h"
15
16#include <new>
17#include <stdlib.h>
18#include <string.h>
19
20
21HIDCollection::HIDCollection(HIDCollection *parent, uint8 type,
22	local_item_state &localState)
23	:	fParent(parent),
24		fType(type),
25		fStringID(localState.string_index),
26		fPhysicalID(localState.designator_index)
27{
28	usage_value usageValue;
29	if (localState.usage_stack != NULL && localState.usage_stack_used > 0)
30		usageValue.u.extended = localState.usage_stack[0].u.extended;
31	else if (localState.usage_minimum_set)
32		usageValue.u.extended = localState.usage_minimum.u.extended;
33	else if (localState.usage_maximum_set)
34		usageValue.u.extended = localState.usage_maximum.u.extended;
35	else if (type == COLLECTION_LOGICAL) {
36		// this is just a logical grouping collection
37		usageValue.u.extended = 0;
38	} else {
39		TRACE_ALWAYS("none of the possible usages for the collection are "
40			"set\n");
41	}
42
43	fUsage = usageValue.u.extended;
44}
45
46
47HIDCollection::~HIDCollection()
48{
49	for (int32 i = 0; i < fChildren.Count(); i++)
50		delete fChildren[i];
51}
52
53
54uint16
55HIDCollection::UsagePage()
56{
57	usage_value value;
58	value.u.extended = fUsage;
59	return value.u.s.usage_page;
60}
61
62
63uint16
64HIDCollection::UsageID()
65{
66	usage_value value;
67	value.u.extended = fUsage;
68	return value.u.s.usage_id;
69}
70
71
72status_t
73HIDCollection::AddChild(HIDCollection *child)
74{
75	if (fChildren.PushBack(child) == B_NO_MEMORY) {
76		TRACE_ALWAYS("no memory when trying to resize collection child list\n");
77	}
78
79	return B_OK;
80}
81
82
83HIDCollection *
84HIDCollection::ChildAt(uint32 index)
85{
86	int32 count = fChildren.Count();
87	if (count < 0 || index >= (uint32)count)
88		return NULL;
89
90	return fChildren[index];
91}
92
93
94uint32
95HIDCollection::CountChildrenFlat(uint8 type)
96{
97	uint32 count = 0;
98	if (type == COLLECTION_ALL || fType == type)
99		count++;
100
101	for (int32 i = 0; i < fChildren.Count(); i++) {
102		HIDCollection *child = fChildren[i];
103		if (child == NULL)
104			continue;
105
106		count += child->CountChildrenFlat(type);
107	}
108
109	return count;
110}
111
112
113HIDCollection *
114HIDCollection::ChildAtFlat(uint8 type, uint32 index)
115{
116	return _ChildAtFlat(type, index);
117}
118
119
120void
121HIDCollection::AddItem(HIDReportItem *item)
122{
123	if (fItems.PushBack(item) == B_NO_MEMORY) {
124		TRACE_ALWAYS("no memory when trying to resize collection items\n");
125	}
126
127}
128
129
130HIDReportItem *
131HIDCollection::ItemAt(uint32 index)
132{
133	int32 count = fItems.Count();
134	if (count < 0 || index >= (uint32)count)
135		return NULL;
136
137	return fItems[index];
138}
139
140
141uint32
142HIDCollection::CountItemsFlat()
143{
144	uint32 count = fItems.Count();
145
146	for (int32 i = 0; i < fChildren.Count(); i++) {
147		HIDCollection *child = fChildren[i];
148		if (child != NULL)
149			count += child->CountItemsFlat();
150	}
151
152	return count;
153}
154
155
156HIDReportItem *
157HIDCollection::ItemAtFlat(uint32 index)
158{
159	return _ItemAtFlat(index);
160}
161
162
163void
164HIDCollection::PrintToStream(uint32 indentLevel)
165{
166	char indent[indentLevel + 1];
167	memset(indent, '\t', indentLevel);
168	indent[indentLevel] = 0;
169
170	const char *typeName = "unknown";
171	switch (fType) {
172		case COLLECTION_PHYSICAL:
173			typeName = "physical";
174			break;
175		case COLLECTION_APPLICATION:
176			typeName = "application";
177			break;
178		case COLLECTION_LOGICAL:
179			typeName = "logical";
180			break;
181		case COLLECTION_REPORT:
182			typeName = "report";
183			break;
184		case COLLECTION_NAMED_ARRAY:
185			typeName = "named array";
186			break;
187		case COLLECTION_USAGE_SWITCH:
188			typeName = "usage switch";
189			break;
190		case COLLECTION_USAGE_MODIFIER:
191			typeName = "usage modifier";
192			break;
193	}
194
195	TRACE_ALWAYS("%sHIDCollection %p\n", indent, this);
196	TRACE_ALWAYS("%s\ttype: %u %s\n", indent, fType, typeName);
197	TRACE_ALWAYS("%s\tusage: 0x%08" B_PRIx32 "\n", indent, fUsage);
198	TRACE_ALWAYS("%s\tstring id: %u\n", indent, fStringID);
199	TRACE_ALWAYS("%s\tphysical id: %u\n", indent, fPhysicalID);
200
201	TRACE_ALWAYS("%s\titem count: %" B_PRIu32 "\n", indent, fItems.Count());
202	for (int32 i = 0; i < fItems.Count(); i++) {
203		HIDReportItem *item = fItems[i];
204		if (item != NULL)
205			item->PrintToStream(indentLevel + 1);
206	}
207
208	TRACE_ALWAYS("%s\tchild count: %" B_PRIu32 "\n", indent, fChildren.Count());
209	for (int32 i = 0; i < fChildren.Count(); i++) {
210		HIDCollection *child = fChildren[i];
211		if (child != NULL)
212			child->PrintToStream(indentLevel + 1);
213	}
214}
215
216
217HIDCollection *
218HIDCollection::_ChildAtFlat(uint8 type, uint32 &index)
219{
220	if (type == COLLECTION_ALL || fType == type) {
221		if (index == 0)
222			return this;
223
224		index--;
225	}
226
227	for (int32 i = 0; i < fChildren.Count(); i++) {
228		HIDCollection *child = fChildren[i];
229		if (child == NULL)
230			continue;
231
232		HIDCollection *result = child->_ChildAtFlat(type, index);
233		if (result != NULL)
234			return result;
235	}
236
237	return NULL;
238}
239
240
241HIDReportItem *
242HIDCollection::_ItemAtFlat(uint32 &index)
243{
244	int32 count = fItems.Count();
245	if (count > 0 && index < (uint32)count)
246		return fItems[index];
247
248	index -= fItems.Count();
249
250	for (int32 i = 0; i < fChildren.Count(); i++) {
251		HIDCollection *child = fChildren[i];
252		if (child == NULL)
253			continue;
254
255		HIDReportItem *result = child->_ItemAtFlat(index);
256		if (result != NULL)
257			return result;
258	}
259
260	return NULL;
261}
262
263
264void
265HIDCollection::BuildReportList(uint8 reportType,
266	HIDReport **reportList, uint32 &reportCount)
267{
268
269	for (int32 i = 0; i < fItems.Count(); i++) {
270		HIDReportItem *item = fItems[i];
271		if (item == NULL)
272			continue;
273
274		HIDReport *report = item->Report();
275		if (reportType != HID_REPORT_TYPE_ANY && report->Type() != reportType)
276			continue;
277
278		bool found = false;
279		for (uint32 j = 0; j < reportCount; j++) {
280			if (reportList[j] == report) {
281				found = true;
282				break;
283			}
284		}
285
286		if (found)
287			continue;
288
289		reportList[reportCount++] = report;
290	}
291
292	for (int32 i = 0; i < fChildren.Count(); i++) {
293		HIDCollection *child = fChildren[i];
294		if (child == NULL)
295			continue;
296
297		child->BuildReportList(reportType, reportList, reportCount);
298	}
299}
300