xref: /haiku/src/add-ons/kernel/drivers/input/hid_shared/HIDCollection.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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 
21 HIDCollection::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 
47 HIDCollection::~HIDCollection()
48 {
49 	for (int32 i = 0; i < fChildren.Count(); i++)
50 		delete fChildren[i];
51 }
52 
53 
54 uint16
55 HIDCollection::UsagePage()
56 {
57 	usage_value value;
58 	value.u.extended = fUsage;
59 	return value.u.s.usage_page;
60 }
61 
62 
63 uint16
64 HIDCollection::UsageID()
65 {
66 	usage_value value;
67 	value.u.extended = fUsage;
68 	return value.u.s.usage_id;
69 }
70 
71 
72 status_t
73 HIDCollection::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 
83 HIDCollection *
84 HIDCollection::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 
94 uint32
95 HIDCollection::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 
113 HIDCollection *
114 HIDCollection::ChildAtFlat(uint8 type, uint32 index)
115 {
116 	return _ChildAtFlat(type, index);
117 }
118 
119 
120 void
121 HIDCollection::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 
130 HIDReportItem *
131 HIDCollection::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 
141 uint32
142 HIDCollection::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 
156 HIDReportItem *
157 HIDCollection::ItemAtFlat(uint32 index)
158 {
159 	return _ItemAtFlat(index);
160 }
161 
162 
163 void
164 HIDCollection::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 
217 HIDCollection *
218 HIDCollection::_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 
241 HIDReportItem *
242 HIDCollection::_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 
264 void
265 HIDCollection::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