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